This tutorial will take a modular approach. The first section will provide an overview of the basic concepts of git. The second section will provide a quick overview of basic usage and the third and final section will cover intermediate level usage. In an attempt to ease understanding, the tutorial will blend together git commands and output, schematic diagrams and commentary in an attempt to ease understanding.
The following table surves as both a key and overview of the most common actions and git ‘verbs’.
git revert "<commit>" where <commit> is a reference to a commit that should be nullified (inverted)
Generate a new commit that reverses the changes introduced by a commit thereby effectively rolling back to a previous state (the one prior to the nominated commit) whilst still maintaining full commit history.
git pull -u <remote> <branch> where <remote> is the name of the remote (typically origin) and <branch> is the branch to sync with remote (typically master).
Pull changes from a branch of a remote repository.
git push -u <remote> <branch> where <remote> is the name of the remote (typically origin) and <branch> is the branch to sync with remote (typically master).
Push changes up to a branch of a remote repository.
1 Context
Git is a distributed versioning system. This means that the complete contents and history of a repository (in simplistic terms a repository is a collection of files and associated metadata) can be completely duplicated across multiple locations.
No doubt you have previously been working on a file (could be a document, spreadsheet, script or any other type of file) and got to a point where you have thought that you are starting to make edits that substantially change the file and therefore have considered saving the new file with a new name that indicates that it is a new version.
In the above diagram, new content is indicated in red and modifications in blue.
Whist this approach is ok, it is fairly limited and unsophisticated approach to versioning (keeping multiple versions of a file). Firstly, if you edit this file over many sessions and each time save with a different name, it becomes very difficult to either keep tract of what changes are associated with each version of the file, or the order in which the changes were made. This is massively compounded if a project comprises multiple files or has multiple authors.
Instead, imagine a system in which you could take a snapshot of state of your files and also provide a description outlining what changes you have made. Now imagine that the system was able to store and keep track of a succession of such versions in such a way that allows you to roll back to any previous versions of the files and exchange the entire history of changes with others collaborators - that is the purpose of git.
In the above diagram (which I must point out is not actually how git works), you can see that we are keeping track of multiple documents and potentially multiple changes within each document. What constitutes a version (as in how many changes and to what files) is completely arbitrary. Each individual edit can define a separate version.
One of the issues with the above system is that there is a lot of redundancy. With each new version an addition copy of the project’s entire filesystem (all its files) must be stored. In the above case, Version 2 and 3 both contain identical copies of fileA.doc. Is there a way of reducing the required size of the snapshots by only keeping copies of those that have actually changed? this is what git achieves. Git versions (or snapshots known as commits) store files that have changed since the previous and files that have not changed are only represented by links to instances of these files within previous snapshots.
Now consider the following:
You might have noticed that a new version can comprise multiple changes across multiple files. However, what if we have made numerous changes to numerous files over the course of an editing session (perhaps simultaneously addressing multiple different editing suggestions at a time), yet we did not want to lump all of these changes together into a single save point (snapshot). For example, the multiple changes might constitute addressing three independent issues, so although all edits were made simultaneously, we wish to record and describe the changes in three separate snapshots.
What if this project had multiple contributors some of whom are working on new components of the project and some whom are working simultaneously on the same set of files? How can the system ensure that all contributors are in sync with each other and that new components are only introduced to the project proper once they are stable and agreed upon?
What if there are files present within our project that we do not wish to keep track of. These files could be log files, compilation intermediates etc.
Given that projects can comprise many files (some of which can be large), is it possible to store compressed files so as to reduce the storage and bandwidth burden?
2 Overview of git
The above discussion provides context for understanding how git works. Within git, files can exist in one of four states:
untracked - these are files within the directory tree that are not to be included in the repository (not part of any snapshot)
modified - these are files that have changed since the last snapshot
staged - these are files that are nominated to be part of the next snapshot
committed - these are files that are represented in a stored snapshot (called a commit). One a snapshot is committed, it is a permanent part of the repositories history
Since untracked files are not part of a repository, we will ignore these for now.
Conceptually, there are three main sections of a repository:
Working directory - (or Workspace) is the obvious tree (set of files and folders) that is present on disc and comprises the actual files that you directly create, edit etc.
Staging area - (or index) is a hidden file that contains metadata about the files to be included in the next snapshot (commit)
Repository - the snapshots (commits). The commits are themselves just additional metadata pointing to a particular snapshot.
A superficial representation of some aspects of the git version control system follows. Here, the physical file tree in the workspace can be added to the staging area before this snapshot can be committed to the local repository.
After we add the two files (file 1 and file 2), both files will be considered in an untracked state. Adding the files to the staging area changes their state to staged. Finally when we commit, the files are in a committed state.
Now if we add another file (file 3) to our workspace, add this file to the staging area and then commit the change, the resulting committed snapshot in the local repository will resemble the workspace. Note, although the staging area contains all three files, only file 3 points to any new internal content - since file 1 and file 2 have unmodified, their instances in the staging area point to the same instances as previous. Similarly, the second commit in the Local repository will point to one new representation (associated with file 3) and two previous representations (associated with file 1 and file 2).
Initially, it might seem that there is an awful lot of duplication going on. For example, if we make a minor alteration to a file, why not just commit the change (delta) instead of an entirely new copy? Well, periodically, git will perform garbage collection on the repository. This process repacks the objects together into a single object that comprises only the original blobs and their subsequent deltas - thereby gaining efficiency. The process of garbage collection can also be forced at any time via:
git gc
During the evolution of most projects, situations arise in which we wish to start work on new components or features that might represent a substantial deviation from the main line of evolution. Often, we would very much like to be able to quarantine the main thread of the project from these new developments. For example, we may wish to be able to continue tweaking the main project files (in order to address minor issues and bugs), while at the same time, performing major edits that take the project in a different direction.
This is called branching. The main evolutionary thread of the project is referred to as the mainbranch. Deviations from the main branch are generally called branches and can be given any name (other than ‘main’ or ‘HEAD’). For example, we could start a new branch called ‘Feature’ where we can evolve the project in one direction whilst still being able to actively develop the main branch at the same time. ‘Feature’ and ‘main’ branches are depicted in the left hand sequence of circles of the schematic below.
The circles represent commits (stored snapshots). We can see that the first commit is the common ancestor of the ‘Feature’ and ‘main’ branch. HEAD is a special reference that points to the tip of the currently active commit. It indicates where the next commit will be built onto. In diagram above, HEAD is pointing to the last commit in main. Hence the next commit will build on this commit. To develop the Featurebranch further, we first have to move HEAD to the tip of the Featurebranch.
We can later merge the Featurebranch into the mainbranch in order to make the new changes mainstream.
To support collaboration, there can also be a remote repository (referred to as origin and depicted by the squares in the figure above). Unlike a local repository, a remote repository does not contain a workspace as files are not directly edited in the remote repository. Instead, the remote repository acts as a permanently available conduit between multiple contributors.
In the diagram above, we can see that the remote repository (origin) has an additional branch (in this called dev). The collaborator whose local repository is depicted above has either not yet obtained (pulled) this branch or has elected not to (as perhaps it is not a direction that they are involved in).
We also see that the mainbranch on the remote repository has a newer (additional) commit than the local repository.
Prior to working on branch a collaborator should first get any updates to the remote repository. This is a two step process. Firstly, the collaborator fetches any changes and then secondly merges those changes into their version of the branch. Collectively, these two actions are called a pull.
To make local changes available to others, the collaborator can pushcommits up to the remote repository. The pushed changes are applied directly to the nominated branch so it is the users responsibility to ensure as much as possible, their local repository already included the most recent remote repository changes (by always pulling before pushing).
To verify that the software is installed and accessible, open a terminal and issue the following:
git--version
git version 2.43.0
Unsure how to open a terminal?
Windows:
On Windows, you can access a terminal via one of the following:
via the command Prompt:
Press Win + R to open the Run dialog.
Type cmd and press Enter.
via PowerShell:
Press Win + X and select “Windows PowerShell.”
Git Bash (Optional):
if Git is installed (which we are hoping it is!), open “Git Bash” for a Unix-like terminal experience.
MacOS:
via Terminal:
Press Cmd + Space to open Spotlight.
Type terminal and press Enter.
Linux:
Oh please. You cannot seriously tell me that you are using Linux and don’t know how to access a terminal.
In the command above, pay particular attention to the number of hyphens in the above command - there are two in a row and no spaces between the -- and the word version.
If you get output similar to above (an indication of what version of git you have on your system), then it is likely to be properly installed. If instead you get an error message, then it is likely that git is not properly installed and you should try again.
4 Getting started
Before using git, it is a good idea to define some global (applied to all your gits) settings. These include your name and email address and whilst not essential, they are applied to all actions you perform so the it is easier for others to track the route of changes etc.
In the above, you should replace “Your Name” with your actual name. This need not be a username (or even a real name) it is not cross referenced anywhere. It is simply to use in collaboration so that your collaborators know who is responsible for your commits.
Similarly, you should replace “your_email@whatever.com” with an email that you are likely to monitor. This need not be the same email address you have used to register a Github account etc, it is just so that collaborators have a way of contacting you.
The remaining sections go through the major git versioning concepts. As previously indicated, git is a command driven program (technically a family of programs). Nevertheless, many other applications (such as RStudio) are able to interface directly with git for some of the more commonly used features. Hence, in addition to providing the command line syntax for performing each task, where possible, this tutorial will also provide instructions (with screen captures) for RStudio and emacs.
5 Setting up (initializing) a new repository
For the purpose of this tutorial, I will create a temporary folder the tmpfolder of my homedirectory into which to create and manipulate repositories. To follow along with this tutorial, you are encouraged to do similarly.
We will start by creating a new directory (folder) which we will call Repo1 in which to place our repository. All usual directory naming rules apply since it is just a regular directory.
mkdir ~/tmp/Repo1
To create (or initialize) a new local repository, issue the git initcommand in the root of the working directory you wish to contain the git repository. This can be either an empty directory or contain an existing directory/file structure. The git initcommand will add a folder called .git to the directory. This is a one time operation.
cd ~/tmp/Repo1git init
Initialized empty Git repository in /home/runner/tmp/Repo1/.git/
The .gitfolder contains all the necessary metadata to manage the repository.
ls-al
total 12
drwxr-xr-x 3 runner docker 4096 Jan 19 04:44 .
drwxr-xr-x 3 runner docker 4096 Jan 19 04:44 ..
drwxr-xr-x 7 runner docker 4096 Jan 19 04:44 .git
this file stores settings such as the location of a remote repository that this repository is linked to.
description
lists the name (and version) of a repository
HEAD
lists a reference to the current checked out commit.
hooks
a directory containing scripts that are executed at various stages (e.g. pre-push.sample is an example of a script executed prior to pushing)
info
contains a file exclude that lists exclusions (files not to be tracked). This is like .gitignore, except is not versioned.
objects
this directory contains SHA indexed files being tracked
refs
a master copy of all the repository refs
logs
contains a history of each branch
The repository that we are going to create in this demonstration could be considered to be a new standalone analysis. In Rstudio, this would be considered a project. So, we will initialise the git repository while we create a new Rstudio project. To do so:
click on the Project selector in the top right of the Rstudio window (as highlighted by the red ellipse in the image below.
select New Project from the dropdown menu
select New Directory form the Create Project panel
select New Project from the Project Type panel
Provide a name for the new directory to be created and use the Browse button to locate a suitable position for this new directory. Ensure that the Create a git repository checkbox is checked
Click the Create Project button
If successful, you should notice a couple of changes - these are highlighted in the following figure:
a new Git tab will appear in the top right panel
the contents of this newly created project/repository will appear in the Files tab of the bottom right panel
If the files and directories that begin with a . do not appear, click on the More file commands cog and make sure the Show Hidden Files option is ticked.
The newly created files/folders are:
.git - this directory houses the repository information and should not generally be edited directly
.gitignore - this file defines files/folders to be excluded from the repository. We will discuss this file more later
.Rhistory - this file will accrue a history of the commands you have evaluated in R within this project
.Rproj.user - this folder stores some project-specific temporary files
Repo1.Rproj - contains the project specific settings
Note that on the left side of the Rstudio window there are two panels - one called “Console”, the other called “Terminal”. The console window is for issuing R commands and the terminal window is for issuing system (bash, shell) commands. Throughout this tutorial, as an alternative to using the point and click Rstudio methods, you could instead issue the Terminal instructions into the “Terminal” panel. Indeed, there are some git commands that are not supported directly by Rstudio and can only be entered into the terminal
Note, at this stage, no files are being tracked, that is, they are not part of the repository.
To assist in gaining a greater understanding of the workings of git, we will use a series of schematics diagrams representing the contents of four important sections of the repository. Typically, these figures will be contained within callout panels that expand/collapse upon clicking. However, for this first time, they will be standalone.
In the first figure below, the left hand panel represents the contents of the root directory (excluding the .git folder) - this is the workspace and is currently empty.
The three white panels represent three important parts of the inner structure of the .git folder. A newly initialized repository is relatively devoid of any specific metadata since there are no staged or committed files. In the root of the .git folder, there is a file called HEAD.
The figure is currently very sparse. However, as the repository grows, so the figure will become more complex.
The second figure provides the same information, yet via a network diagram. Again, this will not be overly meaningful until the repository contains some content.
5.2 Initializing other types of repositories
The above demonstrated how to initialise a new local repository from scratch. However, there are times when we instead want to:
create a git repository from an existing directory or project
collaborate with someone on an existing repository
create a remote repository
These situations are briefly demonstrated in the following sections.
5.2.1 Initializing a shared (remote) repository
The main repository for sharing should not contain the working directory as such - only the .git tree and the .gitignore file. Typically the point of a remote repository is to act as a perminantly available repository from which multiple uses can exchange files. Consequently, those accessing this repository should only be able to interact with the .git metadata - they do not directly modify any files.
Since a remote repository is devode of the working files and directories, it is referred to as bare.
To create a bare remote repository, issue the git init --barecommand after logging in to the remote location.
git init --bare
Use the instructions for the Terminal
5.2.2 Cloning an existing repository
To get your own local copy of an existing repository, issue the git clone <repo url>command in the root of the working directory you wish to contain the git repository. The repo url points to the location of the existing repository to be cloned. This is also a one time operation and should be issued in an otherwise empty directory.
The repo url can be located on any accessible filesytem (local or remote). The cloning process also stores a link back to the original location of the repository (called origin). This provides a convenient way for the system to keep track of where the local repository should exchange files.
Many git repositories are hosted on sites such as github, gitlab or bitbucket. Within an online git repository, these sites provide url links for cloning.
where "url.git" is the url of the hosted repository.
click on the Project selector in the top right of the Rstudio window (as highlighted by the red ellipse in the image below.
select New Project from the dropdown menu
select Version Control form the Create Project panel
select Git from the Create Project from Version Control panel
paste in the address of the repository that you want to clone, optionally a name for this repository (if you do not like the original name) and use the Browse button to locate a suitable position for this new directory.
Click the Create Project button
5.2.3 Initializing a repository in an existing directory
click on the Project selector in the top right of the Rstudio window (as highlighted by the red ellipse in the image below.
select New Project from the dropdown menu
select Existing Directory form the Create Project panel
use the Browse button to locate the existing directory
Click the Create Project button
6 Tracking files
The basic workflow for tracking files is a two step process in which one or more files are first added to the staging area before they are committed to the local repository. The staging area acts as a little like a snapshot of what the repository will look like once the changes have been committed. The staging area also acts like a buffer between the files in the workspace (actual local copy of files) and the local repository (committed changes).
The reason that this is a two step process is that it allows the user to make edits to numerous files, yet block the commits in smaller chunks to help isolate changes in case there is a need to roll back to previous versions.
6.1 Staging files
When a file is first added to the staging area, a full copy of that file is added to the staging area (not just the file diffs as in other versioning systems).
To demonstrate lets create a file (a simple text file containing the string saying ‘File 1’) and add it to the staging area.
echo'File 1'> file1
Now lets add this file to the staging area
git add file1
To see the status of the repository (that is, what files are being tracked), we issue the git statuscommand
git status
On branch main
No commits yet
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: file1
This indicates that there is a single file (file1) in the staging area
To demonstrate lets create a file (a simple text file containing the string saying ‘File 1’) and add it to the staging area.
Click the green “New File” button followed by the “Text File” option (or click the equivalent option from the “File” menu)
Type File 1 in the panel with the flashing cursor. This panel represents the contents of the yet to be named file that we are creating.
Click the “Save” or “Save all” buttons (or select the equivalent items from the “File” menu) and name the file “file1”
Switch to the Git tab and you should notice a number of items (including the file we just created) in the panel. These are files that git is aware of, but not yet tracking. This panel acts as a status window. The yellow “?” symbol indicates that git considers these files “untracked”
To stage a file, click on the corresponding checkbox - the status symbol should change to a green “A” (for added)
Our simple overview schematic represents the staging of file 1.
A schematic of the internal working of git shows in .git/objects a blob has been created. This is a compressed version of file1. Its filename is a 40 digit SHA-1 checksum has representing the contents of the file1. To re-iterate, the blob name is a SHA-1 hash of the file contents (actually, the first two digits form a folder and the remaining 38 form the filename).
We can look at the contents of this blob using the git cat-filecommand. This command outputs the contents of a compressed object (blob, tree, commit) from either the objects name (or unique fraction thereof) or its tag (we will discuss tags later).
git cat-file blob 50fcd
File 1
The add (staging) process also created a index file. This file simply points to the blob that is part of the snapshot. The git internals schematic illustrates the internal changes in response to staging a file.
To commit a set of changes from the staging area to the local repository, we issue the git commitcommand. We usually add the -mswitch to explicitly supply a message to be associated with the commit. This message should ideally describe what the changes the commit introduces to the repository.
We now see that the status has changed. It indicates that the tree in the workspace is in sync with the repository.
git status
On branch main
nothing to commit, working tree clean
To commit a set of changes from the staging area to the local repository:
click on the “Commit” button to open the “Review Changes” window
This box will list the files to be committed (in this case “file1”), the changes in this file since the previous commit (as this is the first time this file has been committed, the changes are the file contents)
you should also provide a commit message (in the figure above, I entered “Initial commit”. This message should ideally describe what the changes the commit introduces to the repository.
click the “Commit” button and you will be presented with a popup message.
This message provides feedback to confirm that your commit was successful.
close the popup window and the “Review Changes” window
file1 should now have disappeared from the git status panel.
Our simple overview schematic represents the staging of file 1.
Additional details about the commit
The following modifications have occurred (in reverse order to how they actually occur):
The mainbranch reference was created. There is currently only a single branch (more on branches later). The branch reference point to (indicates) which commit is the current commit within a branch.
cat .git/refs/heads/main
fbd5ddb880ba91b13658b8747292e53ff05bf0e9
A commit was created. This points to a tree (which itself points to the blob representing file1) as well as other important metadata (such as who made the commit and when). Since the time stamp will be unique each time a snapshot is commited, so too the name of the commit (as a SHA-1 checksum hash) will differ. To reiterate, the names of blobs and trees are determined by contents alone, commit names are also incorporate commit timestamp and details of the committer - and are thus virtually unique.
git cat-file commit fbd5d
tree 07a941b332d756f9a8acc9fdaf58aab5c7a43f64
author pcinereus <i.obesulus@gmail.com> 1705639467 +0000
committer pcinereus <i.obesulus@gmail.com> 1705639467 +0000
Initial repo and added file1
A tree object was created. This represents the directory tree of the snapshot (commit) and thus points to the blobs.
Whenever a file is added or modified, if the changes are to be tracked, the file needs to be added to the staging area. Lets demonstrate by modifying file1 and adding an additional file (file2), this time to a subdirectory (dir1).
On branch main
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
new file: dir1/file2
modified: file1
modify file1 by adding a number of hyphens under the File 1 like in the figure below
save the file. As you do so, you should notice that the file reappears in the status panel (this time with a blue “M” to signify that the file has been modified)
to create the subdirectory, click on the “Add a new folder” icon and then enter a name for the subdirectory in the popup box (as per figure below)
navigate to this new directory (dir1)
click the “Create a new blank file in current directory” button and select “Text file”
enter a new filename (file2) into the popup box
enter some text into this file (like in the figure below)
save the file and notice that the dir1 directory is now also in the git status panel (yet its status is “untracked”)
stage both file1 and dir1 (click on the corresponding checkboxes)
And now our schematic looks like:
Another visual representation of the git
More information about staging changes to the repository
So when staging, the following has been performed:
two new blobs have been generated. One representing the modified file1 and the other representing the newly created file2 in the dir1 folder. The blob that represented the original file1 contents is still present and indeed is still the one currently committed. Blobs are not erased or modified.
git commit -m'Modified file1 and added file2 (in dir1)'
[main 64bffa2] Modified file1 and added file2 (in dir1)
2 files changed, 2 insertions(+)
create mode 100644 dir1/file2
click the “Commit” button
you might like to explore the changes associated with each file
enter a commit message (as in the figure below)
click the “Commit” button
after checking that the “Git Commit” popup does not contain any errors, close the popup
to explore the repository history, click towards the “History” button on the top left corner of the “Review Changes” window
This provides a graphical list of commits (in reverse chronological order)
once you have finished exploring the history, you can close the “Review Changes” window
More information about changes to the repository
The following modifications occur:
the master branch now points to the new commit.
cat .git/refs/heads/main
64bffa244a1123c348ee04c9a10abd1012cb1c9d
git reflog
64bffa2 HEAD@{0}: commit: Modified file1 and added file2 (in dir1)
fbd5ddb HEAD@{1}: commit (initial): Initial repo and added file1
a new commit was created. This points to a new root tree object and also points to the previous commit (its parent).
git cat-file commit 64bff
tree 2b61e2b3db9d1708269cf9d1aeaae2b0a2af1a23
parent fbd5ddb880ba91b13658b8747292e53ff05bf0e9
author pcinereus <i.obesulus@gmail.com> 1705639473 +0000
committer pcinereus <i.obesulus@gmail.com> 1705639473 +0000
Modified file1 and added file2 (in dir1)
new root tree was created. This points to a blob representing the modified file1 as well as a newly created sub-directory tree representing the dir1 folder.
git ls-tree 2b61e
040000 tree f2fa54609fe5e918f365e0d5ffaf9a3aea88d541 dir1
100644 blob 28ed2456cbfa8a18a280c8af5b422e91e88ff64d file1
git cat-file -p HEAD^{tree}
040000 tree f2fa54609fe5e918f365e0d5ffaf9a3aea88d541 dir1
100644 blob 28ed2456cbfa8a18a280c8af5b422e91e88ff64d file1
a new sub-directory root tree was created. This points to a blob representing the modified file1 as well as a newly created subtree tree representing the file2 file within the dir1 folder.
git ls-tree 64bff
040000 tree f2fa54609fe5e918f365e0d5ffaf9a3aea88d541 dir1
100644 blob 28ed2456cbfa8a18a280c8af5b422e91e88ff64d file1
OR,
git ls-tree HEAD
040000 tree f2fa54609fe5e918f365e0d5ffaf9a3aea88d541 dir1
100644 blob 28ed2456cbfa8a18a280c8af5b422e91e88ff64d file1
Another visual representation of the git
More information about committing changes to the repository
Committing staged changes creates an object under the .git tree.
tree 2b61e2b3db9d1708269cf9d1aeaae2b0a2af1a23
parent fbd5ddb880ba91b13658b8747292e53ff05bf0e9
author pcinereus <i.obesulus@gmail.com> 1705639473 +0000
committer pcinereus <i.obesulus@gmail.com> 1705639473 +0000
Modified file1 and added file2 (in dir1)
git cat-file -p HEAD^{tree}
040000 tree f2fa54609fe5e918f365e0d5ffaf9a3aea88d541 dir1
100644 blob 28ed2456cbfa8a18a280c8af5b422e91e88ff64d file1
git log --oneline
64bffa2 Modified file1 and added file2 (in dir1)
fbd5ddb Initial repo and added file1
Now you might be wondering… What if I have modified many files and I want to stage them all. Do I really have to add each file individually? Is there not some way to add multiple files at a time? The answer of course is yes. To stage all files (including those in subdirectories) we issue the git add .command (notice the dot).
git add .
6.4.gitignore
Whilst it is convenient to not have to list every file that you want to be staged (added), what about files that we don’t want to get staged and committed. It is also possible to define a file (called .gitignore) that is a list of files (or file patterns) that are to be excluded when we request all files be added. This functionality is provided via the .gitignorefile that must be in the root of the repository working directory.
For example, we may have temporary files or automatic backup files or files generated as intermediates in a compile process etc that get generated. These files are commonly generated in the process of working with files in a project, yet we do not necessarily wish for them to be tracked. Often these files have very predictable filename pattern (such as ending with a # or ~ symbol or having a specific file extension such as .aux.
As an example, when working with a project in Rstudio, files (such as .Rhistory) and directories (such as .Rproj.user) are automatically added to the file system and thus appear as untracked files in git status.
Hence, we can create a.gitignore to exclude these files/directories. Indeed, if you are using Rstudio, you might have noticed that a .gitignore file was automatically created when you created the project.
Lets start by modifying the file2 and creating a new file f.tmp (that we want to ignore).
navigate to the dir1 directory and open file2 for editing (or just make sure you are on the file2 tab.
edit the file such that it just contains three hyphens (---) before saving the file
in the same dir1 directory add another new text file (f.tmp) and edit this file to contain the word temp (then save the file)
The Git status panel should display both of these as untracked files.
To ignore the f.tmp file, we could either explicitly add this file as a row in a .gitignore file, or else we could supply a wildcard version that will ignore all files ending in .tmp.
click on the gitignore file to open it up for editing
navigate to the end of this file and add a newline containing the text *.tmp
You will notice that this .gitignore file already had items in it before you started editing it. These were added by Rstudio when you first created the new project.
The first item is .Rproj.user and its presence in this file is why it does not appear in the git status panel.
Once we save the .gitignore file, notice how the f.tmp file is similarly removed from the git status panel - since via .gitignore we have indicated that we want to ignore this file (not track it as part of our version control system).
More information about exclusions (.gitignore)
Entry
Meaning
file1
DO NOT stage (add) file1
*.tmp
DO NOT stage (add) any file ending in .tmp
/dir1/*
DO NOT stage (add) the folder called dir1 (or any of its contents) unless this is specifically negated (see next line)
!/dir1/file2
DO stage (add) the file called file2 in the dir1 folder
Now when we go to add all files to the staging area, those that fall under the exclude rules will be ignored
778d70d Modified file2, added .gitignore
64bffa2 Modified file1 and added file2 (in dir1)
fbd5ddb Initial repo and added file1
7 Inspecting a repository
For this section, will will be working on the repository built up in the previous section. If you did not follow along with the previous section, I suggest that you expand the following callout and run the provided code in a terminal.
If you already have the repository, you can ignore the commands to create the repository.
Recall that within the .git environment, files can be in one of four states:
untracked
modified
staged
committed
To inspect the status of files in your workspace, you can issue the git statuscommand (as we have done on numerous occasions above). This command displays the current state of the workspace and staging area.
On branch main
nothing to commit, working tree clean
The output of git status partitions all the files into (staged: Changes to be committed, unstaged: Changes not staged for commit and Untracked) as well as hints on how to either promote or demote the status of these files.
Examine the git status panel - ideally it should be empty thereby signalling that all your important files are tracked andcommitted.
The git logcommand allows us to review the history of committed snapshots
git log
commit 778d70d3a1103eee2740a68cc1d18c516502eece
Author: pcinereus <i.obesulus@gmail.com>
Date: Fri Jan 19 04:44:35 2024 +0000
Modified file2, added .gitignore
commit 64bffa244a1123c348ee04c9a10abd1012cb1c9d
Author: pcinereus <i.obesulus@gmail.com>
Date: Fri Jan 19 04:44:33 2024 +0000
Modified file1 and added file2 (in dir1)
commit fbd5ddb880ba91b13658b8747292e53ff05bf0e9
Author: pcinereus <i.obesulus@gmail.com>
Date: Fri Jan 19 04:44:27 2024 +0000
Initial repo and added file1
We can see that in my case some fool called ‘Murray Logan’ has made a total of three commits. We can also see the date/time that the commits were made as well as the supplied commit comment.
Over time repositories accumulate a large number of commits, to only review the last 2 commits, we could issue the git log -n 2command.
git log -n 2
commit 778d70d3a1103eee2740a68cc1d18c516502eece
Author: pcinereus <i.obesulus@gmail.com>
Date: Fri Jan 19 04:44:35 2024 +0000
Modified file2, added .gitignore
commit 64bffa244a1123c348ee04c9a10abd1012cb1c9d
Author: pcinereus <i.obesulus@gmail.com>
Date: Fri Jan 19 04:44:33 2024 +0000
Modified file1 and added file2 (in dir1)
Additional useful (git log) options
Option
Example
--oneline Condensed view
git log --oneline
778d70d Modified file2, added .gitignore
64bffa2 Modified file1 and added file2 (in dir1)
fbd5ddb Initial repo and added file1
--grep="<pattern>" Filter by regex pattern of commit message
git log --grep="Modified"
commit 778d70d3a1103eee2740a68cc1d18c516502eece
Author: pcinereus <i.obesulus@gmail.com>
Date: Fri Jan 19 04:44:35 2024 +0000
Modified file2, added .gitignore
commit 64bffa244a1123c348ee04c9a10abd1012cb1c9d
Author: pcinereus <i.obesulus@gmail.com>
Date: Fri Jan 19 04:44:33 2024 +0000
Modified file1 and added file2 (in dir1)
<file> Filter by filename
git log file1
commit 64bffa244a1123c348ee04c9a10abd1012cb1c9d
Author: pcinereus <i.obesulus@gmail.com>
Date: Fri Jan 19 04:44:33 2024 +0000
Modified file1 and added file2 (in dir1)
commit fbd5ddb880ba91b13658b8747292e53ff05bf0e9
Author: pcinereus <i.obesulus@gmail.com>
Date: Fri Jan 19 04:44:27 2024 +0000
Initial repo and added file1
--decorate --graph
git log --graph--decorate--oneline
* 778d70d (HEAD -> main) Modified file2, added .gitignore
* 64bffa2 Modified file1 and added file2 (in dir1)
* fbd5ddb Initial repo and added file1
--all All branches
git log --all
commit 778d70d3a1103eee2740a68cc1d18c516502eece
Author: pcinereus <i.obesulus@gmail.com>
Date: Fri Jan 19 04:44:35 2024 +0000
Modified file2, added .gitignore
commit 64bffa244a1123c348ee04c9a10abd1012cb1c9d
Author: pcinereus <i.obesulus@gmail.com>
Date: Fri Jan 19 04:44:33 2024 +0000
Modified file1 and added file2 (in dir1)
commit fbd5ddb880ba91b13658b8747292e53ff05bf0e9
Author: pcinereus <i.obesulus@gmail.com>
Date: Fri Jan 19 04:44:27 2024 +0000
Initial repo and added file1
To explore the history of a repository, click on the clock icon (“View history of previous commits” button). This will open up the “Review Changes” window in the “History” tab.
Along with the reverse chronological list of commits, for each commit (and file thereof), you can explore the changes (diffs) that occurred.
Text that appears over a green background represents text that have been added as part of the current commit. Text that appears over a red background represents text that have been removed.
If we scroll down and explore the changes in dir1/file2 for the most recent commit, we see that the text * Notes was removed and then * Notes and --- were added. At first this might seem a bit odd - why was * Notes deleted and then added back?
Git works on entire lines of text. So the first line was replaced because in the newer version, the first line had a carriage return (newline character). Although we cant see this character, it is there - we see it more via its effect (sending the text after it to the next line). Hence, in fact, two lines of text were actually changed in the most recent commit.
Another way to explore the commit history is to look at the reflog. This is a log of the branch references. This approach is more useful when we have multiple branches and so will be visited in the section on branching. It displays all repository activity, not just the commits.
git reflog
778d70d HEAD@{0}: commit: Modified file2, added .gitignore
64bffa2 HEAD@{1}: commit: Modified file1 and added file2 (in dir1)
fbd5ddb HEAD@{2}: commit (initial): Initial repo and added file1
Some of this sort of information can be gleaned from the git “History”. Just make sure you select (“all branches”) from the “Switch branch” menu.
7.1.3diff
Whilst some of these actions described in this section are available from the “History” tab of the “Review Changes” window in Rstudio, most are only available as terminal commands.
Two of the three commits in our repository involved modifications to a file (dir1/file2). To further help illustrate commands to compare files indifferent states, we will additionally make a further change to dir1/file2. The git diff allows us to explore differences between:
The output indicates that we are comparing the blob representing dir1/file2 in the index (staging area) with the newly modified dir1/file2. The next couple of rows indicate that the indexed version will be represented by a ‘-’ sign and the new version will be represented by a ‘+’ sign. The next row (which is surrounded in a pair of @ signs, indicates that there are two lines that have changed. Finally the next two rows show that a charrage return has been added to the end of the first line and the new version has added the word ‘Notes’ to the next line.
Similar to the previous section, the following is only really available via the terminal.
We can list the files that comprise the repository by:
git ls-files
.gitignore
dir1/file2
file1
The change to dir1/file2 above was just to illustrate the git diff. In doing so we now have a modified version of this file that has not been committed Before we move on, I am going to remove these changes so that the dir1/file2 is not in a modified state and reflects the state of the current commit. To do so, I will use perform a hard reset (git reset --hard). More will be discussed about the git reset command later in this tutorial - for now all that is important is to know that it restores the workspace to a previous state.
In addition to the git reset --hard, I will also clean and prune the repository.
HEAD is now at 778d70d Modified file2, added .gitignore
Source Code
---title: Git and version controlauthor: "Murray Logan"date: "`r format(Sys.time(), '%d %B, %Y')`"format: html: toc: true toc-float: true number-sections: true number-depth: 3 embed-resources: true code-fold: false code-tools: true code-summary: "Show the code"execute: keep-md: truecrossref: fig-title: '**Figure**' fig-labels: arabic tbl-title: '**Table**' tbl-labels: arabicengine: knitrbibliography: resources/references.biboutput_dir: "docs"---```{r setup, include=FALSE,warning=FALSE, message=FALSE}knitr::opts_chunk$set(echo =TRUE,warning=FALSE, message=FALSE, cache =TRUE, comment ="")options(tinytex.engine ='xelatex')cleanRmdInput <-function(x) {#x <- gsub("```\\{r","```markdown\n`r ''```\\{r",x)x <-gsub("^```$","`` `",x) # the Makefile will then change this back to ``` after pandocx}library(tidyverse)library(pander)FIG_PATH <-'10_git_files/figure-html/'```::: {.newsbox}**Other useful tutorials or resources**- [https://git-scm.com/book/en/v2](https://git-scm.com/book/en/v2)- [https://www.atlassian.com/git/tutorials](https://www.atlassian.com/git/tutorials)- [https://marklodato.github.io/visual-git-guide/index-en.html](https://marklodato.github.io/visual-git-guide/index-en.html)- [https://git-scm.com/docs/gittutorial](https://git-scm.com/docs/gittutorial)- [https://marklodato.github.io/visual-git-guide/index-en.html](https://marklodato.github.io/visual-git-guide/index-en.html)- [https://try.github.io/levels/1/challenges/1](https://try.github.io/levels/1/challenges/1)- [https://onlywei.github.io/explain-git-with-d3/](https://onlywei.github.io/explain-git-with-d3/)- [http://git-school.github.io/visualizing-git/](http://git-school.github.io/visualizing-git/)- [https://github.com/sensorflo/git-draw](https://github.com/sensorflo/git-draw):::This tutorial will take a modular approach. The first section willprovide an overview of the basic concepts of git. The second sectionwill provide a quick overview of basic usage and the third and finalsection will cover intermediate level usage. In an attempt to easeunderstanding, the tutorial will blend together git commands andoutput, schematic diagrams and commentary in an attempt to easeunderstanding.The following table surves as both a key and overview of the mostcommon actions and git 'verbs'.```{cat}#| label: common#| echo: true#| eval: true#| cache: true#| engine.opts:#| file: "resources/common.tikz"\tikzstyle{TARGET}=[font={\fontspec[Scale=2]{NotoSans-Regular}}]\tikzstyle{hashText}=[font={\fontspec[Scale=1.5]{Inconsolata}}]\tikzstyle{commentText}=[font={\fontspec[Scale=1.0]{Inconsolata}}]\tikzstyle{refText}=[font={\fontspec[Scale=1.5]{Inconsolata}}]\definecolor{color_branch}{rgb}{1,0.8,0.4}\definecolor{color_head}{HTML}{6495ED}%\definecolor{color_HEAD}{rgb}{0.26,0.65,0.91}\definecolor{color_commit}{rgb}{0.9,0.9,0.2}\definecolor{color_inactive}{rgb}{0.90,0.9,0.9}\definecolor{color_detached}{rgb}{0.90,0.9,0.9}\definecolor{color_derivative}{rgb}{0.12,0.6,0.51}\definecolor{color_local}{rgb}{0.9,0.9,0.2}\definecolor{color_remote}{rgb}{1,0.55,0.15}% A template for making the storage symbol\newcommand{\state}[3]{\draw (#1) node [draw=none,fill=#2,shape=circle,minimum width=2cm](#3){\begin{tikzpicture}\node [draw=white, fill=white,shape=cylinder,shape aspect=1.3,shape border rotate=90,minimum height=1.6cm,minimum width=1.5cm] at (0,0)(Cylinder){};\draw[draw=#2,very thick,line width=0.1cm,anchor=north west]($(Cylinder.north west)+(-0.05cm,-0.1cm)$) arc (-180:0:0.8cm and 0.2cm);\draw[draw=#2,very thick,line width=0.1cm,anchor=north west]($(Cylinder.north west)+(-0.05cm,-0.5cm)$) arc (-180:0:0.8cm and 0.2cm);\draw[draw=#2,very thick,line width=0.1cm,anchor=north west]($(Cylinder.north west)+(-0.05cm,-0.9cm)$) arc (-180:0:0.8cm and 0.2cm);\end{tikzpicture}};}\newcommand{\commit}[5]{\node [#1,inner sep=0,outer sep=0](#2){\begin{tikzpicture}[#1]\draw [#1] node [draw=black!40!#3,fill=#3,shape=circle,minimum width=1.0cm,line width=3pt](x){};%\node [below,hashText] at (x.south){#4};\end{tikzpicture}};\ifx\notempty#4\empty\node [below,hashText, minimum height =0] at (#2.south){#4};\fi\ifx\notempty#5\empty\node [below,commentText,text=gray, minimum height =0] at ($(#2.south)+(0,-0.5)$){#5};\fi}\newcommand{\rcommit}[5]{\node [#1,inner sep=0,outer sep=0](#2){\begin{tikzpicture}[#1]\draw [#1] node [draw=black!40!#3,fill=#3,shape=rectangle,minimum width=1.0cm,minimum height=1.0cm,line width=3pt](x){};%\node [below,hashText] at (x.south){#4};\end{tikzpicture}};\node [below,hashText] at (#2.south){#4};\node [below,commentText,text=gray] at ($(#2.south)+(0,-0.5)$){#5};}\newcommand{\master}[1]{\node [#1,rectangle,fill=color_branch,draw=black!20!color_branch,line width=2pt,refText,minimum height=0.8cm](master){main};}\newcommand{\rmaster}[1]{\node [#1,rectangle,fill=color_branch,draw=black!20!color_branch,line width=2pt,refText,minimum height=0.8cm](rmaster){origin/main};}\newcommand{\branch}[2]{\node [#1,rectangle,fill=color_branch,draw=black!20!color_branch,line width=2pt,refText,minimum height=0.8cm](#2){#2};}\newcommand{\HEAD}[1]{\node [#1,rectangle,fill=color_HEAD,draw=black!20!color_HEAD,line width=2pt,refText,minimum height=0.8cm](HEAD){HEAD};}\newcommand{\rHEAD}[1]{\node [#1,rectangle,fill=color_HEAD,draw=black!20!color_HEAD,line width=2pt,refText,minimum height=0.8cm](rHEAD){origin/HEAD};}``````{tikz}%| label: Fig0%| engine: tikz%| echo: false%| cache: true%| include: false%| dependson: common%| class: tikz%| engine-opts:%| template: "resources/tikz-minimal.tex"\input{resources/common.tikz}\begin{tikzpicture}%[every node/.style={inner sep=0,outer sep=0, minimum height = 0}]\commit{}{A}{white}{}{}\draw [-,line width=3pt,draw=black!60] (A) -- ++(-1,0);\end{tikzpicture}``````{bash}#| label: Fig0-conv#| warning: false#| message: false#| include: false#| cache: false#| echo: falseconvert-trim +repage -density 300 -resize 20% 10_git_files/figure-html/Fig0-1.pdf 10_git_files/figure-html/Fig0-1.png ``````{tikz}%| label: Fig1%| engine: tikz%| echo: false%| cache: true%| include: false%| dependson: common%| class: tikz%| engine-opts:%| template: "resources/tikz-minimal.tex"\input{resources/common.tikz}\begin{tikzpicture}[every node/.style={inner sep=0,outer sep=0, minimum height = 0}]\commit{}{A}{color_commit!30}{}{}\draw [-,line width=3pt,draw=black!60] (A) -- ++(-1,0);\end{tikzpicture}``````{bash}#| label: Fig1-conv#| warning: false#| message: false#| include: false#| cache: false#| echo: falseconvert-trim +repage -density 300 -resize 20% 10_git_files/figure-html/Fig1-1.pdf 10_git_files/figure-html/Fig1-1.png``````{tikz}%| label: Fig2%| engine: tikz%| echo: false%| cache: true%| include: false%| dependson: common%| class: tikz%| engine-opts:%| template: "resources/tikz-minimal.tex"\input{resources/common.tikz}\begin{tikzpicture}[every node/.style={inner sep=0,outer sep=0, minimum height = 0}]\commit{}{A}{color_commit}{}{}\draw [-,line width=3pt,draw=black!60] (A) -- ++(-1,0);\end{tikzpicture}``````{bash}#| label: Fig2-conv#| warning: false#| message: false#| include: false#| cache: false#| echo: falseconvert-trim +repage -density 300 -resize 20% 10_git_files/figure-html/Fig2-1.pdf 10_git_files/figure-html/Fig2-1.png``````{tikz}%| label: Fig3a%| engine: tikz%| echo: false%| cache: true%| include: false%| dependson: common%| class: tikz%| engine-opts:%| template: "resources/tikz-minimal.tex"\input{resources/common.tikz}\begin{tikzpicture}%[every node/.style={inner sep=0,outer sep=0, minimum height = 0}]\commit{}{A}{color_inactive}{}{}\commit{right = 1cm of A}{B}{color_commit}{}{}\commit{right = 1cm of B}{C}{color_detached}{}{}\draw [-,line width=3pt,draw=black!60] (A) -- ++(-1,0);\draw [-,line width=3pt,draw=black!60] (B) -- (A);\end{tikzpicture}``````{bash}#| label: Fig3a-conv#| warning: false#| message: false#| include: false#| cache: false#| echo: falseconvert-trim +repage -density 300 -resize 20% 10_git_files/figure-html/Fig3a-1.pdf 10_git_files/figure-html/Fig3a-1.png ``````{tikz}%| label: Fig3b%| engine: tikz%| echo: false%| cache: true%| include: false%| dependson: common%| class: tikz%| engine-opts:%| template: "resources/tikz-minimal.tex"\input{resources/common.tikz}\begin{tikzpicture}%[every node/.style={inner sep=0,outer sep=0, minimum height = 0}]\commit{}{A}{color_inactive}{}{}\commit{right = 1cm of A}{B}{color_commit}{}{}\commit{right = 1cm of B}{C}{color_detached!30}{}{}\draw [-,line width=3pt,draw=black!60] (A) -- ++(-1,0);\draw [-,line width=3pt,draw=black!60] (B) -- (A);\draw [->,dashed,line width=3pt,draw=black!60] (C) -- (B);\end{tikzpicture}``````{bash}#| label: Fig3b-conv#| warning: false#| message: false#| include: false#| cache: false#| echo: falseconvert-trim +repage -density 300 -resize 20% 10_git_files/figure-html/Fig3b-1.pdf 10_git_files/figure-html/Fig3b-1.png ``````{tikz}%| label: Fig3c%| engine: tikz%| echo: false%| cache: true%| include: false%| dependson: common%| class: tikz%| engine-opts:%| template: "resources/tikz-minimal.tex"\input{resources/common.tikz}\begin{tikzpicture}%[every node/.style={inner sep=0,outer sep=0, minimum height = 0}]\commit{}{A}{color_inactive}{}{}\commit{right = 1cm of A}{B}{color_inactive}{}{}\commit{right = 1cm of B}{C}{color_commit}{}{}\draw [-,line width=3pt,draw=black!60] (A) -- ++(-1,0);\draw [-,line width=3pt,draw=black!60] (B) -- (A);\draw [-,line width=3pt,draw=black!60] (C) -- (B);\draw [->,line width=3pt,draw=black!60] (A) to[out=45] (C);\end{tikzpicture}``````{bash}#| label: Fig3c-conv#| warning: false#| message: false#| include: false#| cache: false#| echo: falseconvert-trim +repage -density 300 -resize 20% 10_git_files/figure-html/Fig3c-1.pdf 10_git_files/figure-html/Fig3c-1.png ``````{tikz}%| label: Fig4%| engine: tikz%| echo: false%| cache: true%| include: false%| dependson: common%| class: tikz%| engine-opts:%| template: "resources/tikz-minimal.tex"\input{resources/common.tikz}\tikzstyle{refText} = [font={\fontspec[Scale=1.5]{InconsolataSemiCondensed-Regular}}]\begin{tikzpicture}%[every node/.style={inner sep=0,outer sep=0, minimum height = 0}]\commit{}{A}{color_inactive}{}{}\commit{right = 1cm of A}{B}{color_inactive}{}{}\commit{right = 1cm of B}{C}{color_commit}{}{}\draw [-,line width=3pt,draw=black!60] (A) -- ++(-1,0);\draw [-,line width=3pt,draw=black!60] (B) -- (A);\draw [-,line width=3pt,draw=black!60] (C) -- (B);\commit{above = 0.5cm of B}{D}{color_branch}{}{}\draw [-,line width=3pt,draw=black!60] (A.east) to[out=0,in=180] (D);%\node[right = 0.5cm of C, rectangle, refText] (master) {main};\master{right = 0.5cm of C}\draw[->,line width=3pt,draw=black!60] (master) -- (C);\branch{right = 0.5cm of D}{Feature} \draw[->,line width=3pt,draw=black!60] (Feature) -- (D);\end{tikzpicture}``````{bash}#| label: Fig4-conv#| warning: false#| message: false#| include: false#| cache: false#| echo: falseconvert-trim +repage -density 300 -resize 20% 10_git_files/figure-html/Fig4-1.pdf 10_git_files/figure-html/Fig4-1.png ``````{tikz}%| label: Fig5%| engine: tikz%| echo: false%| cache: true%| include: false%| dependson: common%| class: tikz%| engine-opts:%| template: "resources/tikz-minimal.tex"\input{resources/common.tikz}\tikzstyle{refText} = [font={\fontspec[Scale=1.5]{InconsolataSemiCondensed-Regular}}]\begin{tikzpicture}%[every node/.style={inner sep=0,outer sep=0, minimum height = 0}]\commit{}{A}{color_inactive}{}{}\commit{right = 1cm of A}{B}{color_inactive}{}{}\commit{right = 1cm of B}{C}{color_commit}{}{}\draw [-,line width=3pt,draw=black!60] (A) -- ++(-1,0);\draw [-,line width=3pt,draw=black!60] (B) -- (A);\draw [-,line width=3pt,draw=black!60] (C) -- (B);\commit{above = 0.5cm of B}{D}{color_inactive}{}{}\draw [-,line width=3pt,draw=black!60] (A.east) to[out=0,in=180] (D);\master{right = 0.5cm of C}\draw[->,line width=3pt,draw=black!60] (master) -- (C);\branch{right = 0.5cm of D}{Feature}\draw[->,line width=3pt,draw=black!60] (Feature) -- (D);\draw [-,line width=3pt,draw=black!60] (D.east) to[out=0,in=180] (C);\end{tikzpicture}``````{bash}#| label: Fig5-conv#| cache: false#| echo: falseconvert-trim +repage -density 300 -resize 20% 10_git_files/figure-html/Fig5-1.pdf 10_git_files/figure-html/Fig5-1.png ``````{tikz}%| label: Fig6a%| engine: tikz%| echo: false%| cache: true%| include: false%| dependson: common%| class: tikz%| engine-opts:%| template: "resources/tikz-minimal.tex"\input{resources/common.tikz}\tikzstyle{refText} = [font={\fontspec[Scale=1.5]{InconsolataSemiCondensed-Regular}}]\begin{tikzpicture}%[every node/.style={inner sep=0,outer sep=0, minimum height = 0}]\commit{}{A}{color_inactive}{}{}\commit{right = 1cm of A}{B}{color_detached!30}{}{}\commit{right = 1cm of B}{C}{color_commit}{}{}\draw [-,line width=3pt,draw=black!60] (A) -- ++(-1,0);\draw [-,line width=3pt,draw=black!60] (C) -- (A);\end{tikzpicture}``````{bash}#| label: Fig6a-conv#| cache: false#| echo: falseconvert-trim +repage -density 300 -resize 20% 10_git_files/figure-html/Fig6a-1.pdf 10_git_files/figure-html/Fig6a-1.png ``````{tikz}%| label: Fig5b%| engine: tikz%| echo: false%| cache: true%| include: false%| dependson: common%| class: tikz%| engine-opts:%| template: "resources/tikz-minimal.tex"\input{resources/common.tikz}\tikzstyle{refText} = [font={\fontspec[Scale=1.5]{InconsolataSemiCondensed-Regular}}]\begin{tikzpicture}%[every node/.style={inner sep=0,outer sep=0, minimum height = 0}]\commit{}{A}{color_commit}{}{}\draw [-,line width=3pt,draw=black!60] (A) -- ++(-1,0);%\commit{right = 1cm of A}{B}{color_commit}{}{}%\draw [-,line width=3pt,draw=black!60] (B) -- (A);\master{right = 0.5cm of A}\draw[->,line width=3pt,draw=black!60] (master) -- (A);\rcommit{below = 1cm of A}{rA}{color_inactive}{}{}\draw [-,line width=3pt,draw=black!60] (rA) -- ++(-1,0);\rcommit{right = 1cm of rA}{rB}{color_commit}{}{}\draw [-,line width=3pt,draw=black!60] (rB) -- (rA);\rmaster{right = 0.5cm of rB}\draw[->,line width=3pt,draw=black!60] (rmaster) -- (rB);\draw [<-,line width=3pt, draw=black!60, dashed] (A) -- (rB);\end{tikzpicture}``````{bash}#| label: Fig5b-conv#| cache: false#| echo: falseconvert-trim +repage -density 300 -resize 20% 10_git_files/figure-html/Fig5b-1.pdf 10_git_files/figure-html/Fig5b-1.png ``````{tikz}%| label: Fig5a%| engine: tikz%| echo: false%| cache: true%| include: false%| dependson: common%| class: tikz%| engine-opts:%| template: "resources/tikz-minimal.tex"\input{resources/common.tikz}\tikzstyle{refText} = [font={\fontspec[Scale=1.5]{InconsolataSemiCondensed-Regular}}]\begin{tikzpicture}%[every node/.style={inner sep=0,outer sep=0, minimum height = 0}]\commit{}{A}{color_inactive}{}{}\draw [-,line width=3pt,draw=black!60] (A) -- ++(-1,0);\commit{right = 1cm of A}{B}{color_commit}{}{}\draw [-,line width=3pt,draw=black!60] (B) -- (A);\master{right = 0.5cm of B}\draw[->,line width=3pt,draw=black!60] (master) -- (B);\rcommit{below = 1cm of A}{rA}{color_commit}{}{}\draw [-,line width=3pt,draw=black!60] (rA) -- ++(-1,0);\rmaster{right = 0.5cm of rA}\draw[->,line width=3pt,draw=black!60] (rmaster) -- (rA);\draw [->,line width=3pt, draw=black!60, dashed] (B) -- (rA);\end{tikzpicture}``````{bash}#| label: Fig5a-conv#| cache: false#| echo: falseconvert-trim +repage -density 300 -resize 20% 10_git_files/figure-html/Fig5a-1.pdf 10_git_files/figure-html/Fig5a-1.png```<tableclass="table-sm table-borderless"style='border-spacing:20px;'><tr><td><ahref="#Initialize">Initialize git</a><br></td><tdwidth='40%'>`git init`</td><td>Establish a git repository (within the current path if no path provided)</td></tr><tr><td><ahref="#Commit">Staging</a><br></td><td>`git add <file>`<br>where `file` is one or more files to stage</td><td>Staging is indicating which files and their states are to be included in the next commit.</td></tr><tr><td><ahref="#Commit">Committing</a><br></td><td>`git commit -m "<Commit message>"`<br>where `<Commit message>` is a message to accompany the commit</td><td>Commiting generates a 'snapshot' of the file system.</td></tr><tr><td><ahref="#checkout">Checkout</a><br></td><td>`git checkout "<commit>"`<br> where `<commit>` is a reference to a commit to be reviewed</td><td> Explore the state associated with a specific commit</td></tr><tr><td><ahref="#reset">Reset</a><br><!-- <img src="10_git_files/figure-html/Fig3b-1.png" class="" alt="" style="transform: scale(0.2);"/> --></td><td>`git reset --hard "<commit>"`<br> where `<commit>` is a reference to a commit</td><td> Return to a previous state, effectively erasing subsequent commits..</td></tr><tr><td><ahref="#revert">Revert</a><br></td><td>`git revert "<commit>"`<br> where `<commit>` is a reference to a commit that should be nullified (inverted)</td><td> Generate a new commit that reverses the changes introduced by a commit thereby effectively rolling back to a previous state (the one prior to the nominated commit) whilst still maintaining full commit history.</td></tr><tr><td><ahref="#Branching">Branching</a><br></td><td>`git branch <name>`<br>`git checkout <name>`<br> where `<name>` is a reference to a branch name (e.g. 'Feature')</td><td> Take edits in the project in a new direction to allow for modifications that will not affect the main (master) branch.</td></tr><tr><td><ahref="#Merging">Merging</a><br></td><td>`git checkout master`<br>`git branch <name>`<br> where `<name>` is a reference to a branch name (e.g. 'Feature') that is to be merged back into `master`.</td><td> Incorporate changes in a branch into another branch (typically `master`).</td></tr><tr><td><ahref="#rebase">Rebasing</a><br></td><td>`git rebase -i HEAD~<number>`<br> where `<number>` is the number of previous commits to squash together with head.</td><td> Combine multiple commits together into a single larger commit.</td></tr><tr><td><ahref="#Pulling">Pulling</a><br></td><td>`git pull -u <remote> <branch>`<br> where `<remote>` is the name of the remote (typically `origin`) and `<branch>` is the branch to sync with remote (typically `master`).</td><td> Pull changes from a branch of a remote repository.</td></tr><tr><td><ahref="#Pushing">Pushing</a><br></td><td>`git push -u <remote> <branch>`<br> where `<remote>` is the name of the remote (typically `origin`) and `<branch>` is the branch to sync with remote (typically `master`).</td><td> Push changes up to a branch of a remote repository.</td></tr></table># ContextGit is a distributed versioning system. This means that the completecontents and history of a repository (in simplistic terms a repositoryis a collection of files and associated metadata) can be completelyduplicated across multiple locations.No doubt you have previously been working on a file (could be adocument, spreadsheet, script or any other type of file) and got to apoint where you have thought that you are starting to make edits thatsubstantially change the file and therefore have considered saving thenew file with a new name that indicates that it is a new version.```{tikz}%| label: Fig10%| engine: tikz%| echo: false%| cache: true%| class: tikz%| engine-opts:%| template: "resources/tikz-minimal.tex"\tikzstyle{CODE} = [font={\fontspec[Scale=2]{InconsolataSemiCondensed-Regular}}]\tikzstyle{fileText} = [font={\fontspec[Scale=1]{InconsolataSemiCondensed-Regular}}] \definecolor{color_workspace}{rgb}{0.12,0.6,0.51}\definecolor{color_index}{rgb}{0.78,0.86,0.27}\definecolor{color_local}{rgb}{0.9,0.9,0.2}\definecolor{color_remote}{rgb}{1,0.55,0.15}\definecolor{color_master}{rgb}{0.36,0.27,0.87}\definecolor{color_head}{HTML}{6495ED} %\definecolor{color_head}{rgb}{0.26,0.65,0.91}\newcommand{\file}[3] {\coordinate (#3) at (#1);\draw [anchor=top left](#1) rectangle ++(1.5,-2);\draw [fill=color_workspace]($(#1) +(1.5,0)$) -- ++(0,-0.5) --++(-0.5,0.5) -- cycle; \node [anchor=north west,fileText] at ($(#1) +(0,-0.5)$) {#2};}\begin{tikzpicture}\file{0,0}{\begin{minipage}{1.3cm}\textcolor{red}{- item 1}\\\textcolor{red}{- item 2}\end{minipage}}{F1}\node [fileText] at ($(F1) + (0.75,0.3)$) {Version 1};\node [fileText] at ($(F1) + (0.75,-2.3)$) {todo.txt};\file{2,0}{\begin{minipage}{1.3cm}- item 1\\- item 2\\\textcolor{red}{- item 3}\end{minipage}}{F2}\node [fileText] at ($(F2) + (0.75,0.3)$) {Version 2};\node [fileText] at ($(F2) + (0.75,-2.3)$) {todo2.txt};\file{4,0}{\begin{minipage}{1.3cm}- item 1\\- item 2\\- item 3\\\textcolor{red}{- item 4}\end{minipage}}{F3}\node [fileText] at ($(F3) + (0.75,0.3)$) {Version 3};\node [fileText] at ($(F3) + (0.75,-2.3)$) {todo3.txt};\file{6,0}{\begin{minipage}{1.3cm}- item 1\\- item 2\\\textcolor{blue}{- item 4}\end{minipage}}{F4}\node [fileText] at ($(F4) + (0.75,0.3)$) {Version 4};\node [fileText] at ($(F4) + (0.75,-2.3)$) {todo4.txt};\node [fileText] at ($(F4) +(3.5,-1)$) {\begin{minipage}{2.5cm}An example of a poor, adhoc versioning system.\end{minipage}};)\end{tikzpicture}```In the above diagram, new content is indicated in red andmodifications in blue.Whist this approach is ok, it is fairly limited and unsophisticatedapproach to versioning (keeping multiple versions of a file). Firstly,if you edit this file over many sessions and each time save with adifferent name, it becomes very difficult to either keep tract of whatchanges are associated with each version of the file, or the order inwhich the changes were made. This is massively compounded if a projectcomprises multiple files or has multiple authors.Instead, imagine a system in which you could take a snapshot of stateof your files and also provide a description outlining what changesyou have made. Now imagine that the system was able to store and keeptrack of a succession of such versions in such a way that allows youto roll back to any previous versions of the files and exchange theentire history of changes with others collaborators - that is thepurpose of git.```{tikz}%| label: Fig11%| engine: tikz%| echo: false%| cache: true%| class: tikz%| engine-opts:%| template: "resources/tikz-minimal.tex"\tikzstyle{CODE} = [font={\fontspec[Scale=2]{InconsolataSemiCondensed-Regular}}]\tikzstyle{fileText} = [font={\fontspec[Scale=1]{InconsolataSemiCondensed-Regular}}] \definecolor{color_workspace}{rgb}{0.12,0.6,0.51}\definecolor{color_index}{rgb}{0.78,0.86,0.27}\definecolor{color_local}{rgb}{0.9,0.9,0.2}\definecolor{color_remote}{rgb}{1,0.55,0.15}\definecolor{color_master}{rgb}{0.36,0.27,0.87}\definecolor{color_head}{HTML}{6495ED} %\definecolor{color_head}{rgb}{0.26,0.65,0.91}\newcommand{\file}[3] {\coordinate (#3) at (#1);\draw [anchor=top left](#1) rectangle ++(1.5,-2);\draw [fill=color_workspace]($(#1) +(1.5,0)$) -- ++(0,-0.5) --++(-0.5,0.5) -- cycle; \node [anchor=north west,fileText] at ($(#1) +(0,-0.5)$) {#2};}\begin{tikzpicture}%Version 1\file{0,0}{\begin{minipage}{1.3cm}\textcolor{red}{- item 1}\\\textcolor{red}{- item 2}\end{minipage}}{F1}\node [fileText] at ($(F1) + (0.75,-2.3)$) {todo.txt};\file{0,-3}{\begin{minipage}{1.3cm}\textcolor{red}{Title}\\[1em]\textcolor{red}{content}\end{minipage}}{F1a}\node [fileText] at ($(F1a) + (0.75,-2.3)$) {fileA.doc};\node [fileText] at ($(F1) + (0.2,0.5)$) (V1) {Version 1};\draw (V1.200) -- (V1.200 |- F1a);\draw (V1.200 |- F1) -- (F1);\draw (V1.200 |- F1a) -- (F1a);%Version 2\file{3,0}{\begin{minipage}{1.3cm}- item 1\\- item 2\\\textcolor{red}{- item 3}\end{minipage}}{F2}\node [fileText] at ($(F2) + (0.75,-2.3)$) {todo.txt};\file{3,-3}{\begin{minipage}{1.3cm}\textcolor{black}{Title}\\[1em]\textcolor{black}{content}\end{minipage}}{F2a}\node [fileText] at ($(F2a) + (0.75,-2.3)$) {fileA.doc};\file{3,-6}{\begin{minipage}{1.3cm}\textcolor{red}{ID,Num}\\\textcolor{red}{1,10}\\\textcolor{red}{2,15}\end{minipage}}{F2b}\node [fileText] at ($(F2b) + (0.75,-2.3)$) {fileB.csv};\node [fileText] at ($(F2) + (0.2,0.5)$) (V2) {Version 2};\draw (V2.200) -- (V2.200 |- F2b);\draw (V2.200 |- F2) -- (F2);\draw (V2.200 |- F2a) -- (F2a);\draw (V2.200 |- F2b) -- (F2b);%Version 3\file{6,0}{\begin{minipage}{1.3cm}- item 1\\- item 2\\- item 3\\\textcolor{red}{- item 4}\end{minipage}}{F3}\node [fileText] at ($(F3) + (0.75,-2.3)$) {todo.txt};\file{6,-3}{\begin{minipage}{1.3cm}\textcolor{black}{Title}\\[1em]\textcolor{black}{content}\end{minipage}}{F3a}\node [fileText] at ($(F3a) + (0.75,-2.3)$) {fileA.doc};\file{6,-6}{\begin{minipage}{1.3cm}\textcolor{black}{ID,Num}\\\textcolor{black}{1,10}\\2,\textcolor{blue}{25}\end{minipage}}{F3b}\node [fileText] at ($(F3b) + (0.75,-2.3)$) {fileB.csv};\node [fileText] at ($(F3) + (0.2,0.5)$) (V3) {Version 3};\draw (V3.200) -- (V3.200 |- F3b);\draw (V3.200 |- F3) -- (F3);\draw (V3.200 |- F3a) -- (F3a);\draw (V3.200 |- F3b) -- (F3b);\node [fileText] at ($(F3) +(4,-1)$) {\begin{minipage}{3cm}An example of a more sophisticated versioning system\end{minipage}};\end{tikzpicture}```In the above diagram (which I must point out is **not actually howgit works**), you can see that we are keeping track of multipledocuments and potentially multiple changes within each document. Whatconstitutes a version (as in how many changes and to what files) iscompletely arbitrary. Each individual edit can define a separateversion.One of the issues with the above system is that there is a lot ofredundancy. With each new version an addition copy of the project'sentire filesystem (all its files) must be stored. In the above case,Version 2 and 3 both contain identical copies of`fileA.doc`. Is there a way of reducing the required sizeof the snapshots by only keeping copies of those that have actuallychanged? **this is what git achieves**. Git versions (or snapshotsknown as _commits_) store files that have changed since theprevious and files that have not changed are only represented by linksto instances of these files within previous snapshots.```{tikz}%| label: Fig12%| engine: tikz%| echo: false%| cache: true%| class: tikz%| engine-opts:%| template: "resources/tikz-minimal.tex"\tikzstyle{CODE} = [font={\fontspec[Scale=2]{InconsolataSemiCondensed-Regular}}]\tikzstyle{fileText} = [font={\fontspec[Scale=1]{InconsolataSemiCondensed-Regular}}] \definecolor{color_workspace}{rgb}{0.12,0.6,0.51}\definecolor{color_index}{rgb}{0.78,0.86,0.27}\definecolor{color_local}{rgb}{0.9,0.9,0.2}\definecolor{color_remote}{rgb}{1,0.55,0.15}\definecolor{color_master}{rgb}{0.36,0.27,0.87}\definecolor{color_head}{HTML}{6495ED} %\definecolor{color_head}{rgb}{0.26,0.65,0.91}\newcommand{\file}[3] {\coordinate (#3) at (#1);\draw [anchor=top left](#1) rectangle ++(1.5,-2);\draw [fill=color_workspace]($(#1) +(1.5,0)$) -- ++(0,-0.5) --++(-0.5,0.5) -- cycle; \node [anchor=north west,fileText] at ($(#1) +(0,-0.5)$) {#2};}\begin{tikzpicture}%Version 1\file{0,0}{\begin{minipage}{1.3cm}\textcolor{red}{- item 1}\\\textcolor{red}{- item 2}\end{minipage}}{F1}\node [fileText] at ($(F1) + (0.75,-2.3)$) {todo.txt};\file{0,-3}{\begin{minipage}{1.3cm}\textcolor{red}{Title}\\[1em]\textcolor{red}{content}\end{minipage}}{F1a}\node [fileText] at ($(F1a) + (0.75,-2.3)$) {fileA.doc};\node [fileText] at ($(F1) + (0.2,0.5)$) (V1) {Version 1};\draw (V1.200) -- (V1.200 |- F1a);\draw (V1.200 |- F1) -- (F1);\draw (V1.200 |- F1a) -- (F1a);%Version 2\file{3,0}{\begin{minipage}{1.3cm}- item 1\\- item 2\\\textcolor{red}{- item 3}\end{minipage}}{F2}\node [fileText] at ($(F2) + (0.75,-2.3)$) {todo.txt};\file{3,-3}{\begin{minipage}{1.3cm}\textcolor{black}{Title}\\[1em]\textcolor{black}{content}\end{minipage}}{F2a}\node [fileText] at ($(F2a) + (0.75,-2.3)$) {fileA.doc};\file{3,-6}{\begin{minipage}{1.3cm}\textcolor{red}{ID,Num}\\\textcolor{red}{1,10}\\\textcolor{red}{2,15}\end{minipage}}{F2b}\node [fileText] at ($(F2b) + (0.75,-2.3)$) {fileB.csv};\node [fileText] at ($(F2) + (0.2,0.5)$) (V2) {Version 2};\draw (V2.200) -- (V2.200 |- F2b);\draw (V2.200 |- F2) -- (F2);\draw (V2.200 |- F2a) -- (F2a);\draw (V2.200 |- F2b) -- (F2b);%Version 3\file{6,0}{\begin{minipage}{1.3cm}- item 1\\- item 2\\- item 3\\\textcolor{red}{- item 4}\end{minipage}}{F3}\node [fileText] at ($(F3) + (0.75,-2.3)$) {todo.txt};%\file{6,-3}{\begin{minipage}{1.3cm}\textcolor{black}{Title}\\[1em]\textcolor{black}{content}\end{minipage}}{F3a}\node [anchor=west,text=green!50!black!50] at (6,-3) (F3a) {\#\#\#\#\#\#}; \node [fileText] at ($(F3 |- F3a) + (0.75,-0.5)$) {fileA.doc};\draw[->,very thick,color=green!50!black!50] (F3a) -- ($(F2a) +(1.6,-0.5)$);\file{6,-6}{\begin{minipage}{1.3cm}\textcolor{black}{ID,Num}\\\textcolor{black}{1,10}\\2,\textcolor{blue}{25}\end{minipage}}{F3b}\node [fileText] at ($(F3b) + (0.75,-2.3)$) {fileB.csv};\node [fileText] at ($(F3) + (0.2,0.5)$) (V3) {Version 3};\draw (V3.200) -- (V3.200 |- F3b);\draw (V3.200 |- F3) -- (F3);\draw (V3.200 |- F3a) -- (F3a);\draw (V3.200 |- F3b) -- (F3b);\node [fileText] at ($(F3) +(4,-1)$) {\begin{minipage}{3cm}An example of a more sophisticated, yet efficient versioning system\end{minipage}};\end{tikzpicture}```Now consider the following:- You might have noticed that a new version can comprise multiple changes across multiple files. However, what if we have made numerous changes to numerous files over the course of an editing session (perhaps simultaneously addressing multiple different editing suggestions at a time), yet we did not want to lump all of these changes together into a single save point (snapshot). For example, the multiple changes might constitute addressing three independent issues, so although all edits were made simultaneously, we wish to record and describe the changes in three separate snapshots. - What if this project had multiple contributors some of whom are working on new components of the project and some whom are working simultaneously on the same set of files? How can the system ensure that all contributors are in sync with each other and that new components are only introduced to the project proper once they are stable and agreed upon?- What if there are files present within our project that we do not wish to keep track of. These files could be log files, compilation intermediates etc.- Given that projects can comprise many files (some of which can be large), is it possible to store compressed files so as to reduce the storage and bandwidth burden?# Overview of gitThe above discussion provides context for understanding how git works.Within git, files can exist in one of four states:- **untracked** - these are files within the directory tree that are not to be included in the repository (not part of any snapshot)- **modified** - these are files that have changed since the last snapshot- **staged** - these are files that are nominated to be part of the next snapshot- **committed** - these are files that are represented in a stored snapshot (called a _commit_). One a snapshot is committed, it is a permanent part of the repositories historySince untracked files are not part of a repository, we will ignorethese for now.Conceptually, there are three main sections of a repository:- **Working directory** - (or **Workspace**) is the obvious tree (set of files and folders) that is present on disc and comprises the actual files that you directly create, edit etc.- **Staging area** - (or **index**) is a hidden file that contains metadata about the files to be included in the next snapshot (commit)- **Repository** - the snapshots (commits). The commits are themselves just additional metadata pointing to a particular snapshot.A superficial representation of some aspects of the git versioncontrol system follows. Here, the physical file tree in the_workspace_ can be added to the _staging area_ before this snapshotcan be committed to the _local repository_.After we add the two files (`file 1` and `file 2`), both files will beconsidered in an _untracked_ state. Adding the files to the _stagingarea_ changes their state to _staged_. Finally when we commit, thefiles are in a _committed_ state.```{tikz}%| label: Fig13%| engine: tikz%| echo: false%| cache: true%| class: tikz%| engine-opts:%| template: "resources/tikz-minimal.tex"\usetikzlibrary{shapes,arrows,shadows,positioning,mindmap,backgrounds,decorations, calc,fit, decorations.pathreplacing,decorations.pathmorphing, shadings,shapes.geometric,patterns} \usetikzlibrary{arrows.meta}\tikzstyle{TARGET} = [font={\fontspec[Scale=2]{NotoSans-Regular}}] \tikzstyle{CODE} = [font={\fontspec[Scale=2]{InconsolataSemiCondensed-Regular}}]\tikzstyle{TREE} = [font={\fontspec[Scale=1.5]{InconsolataSemiCondensed-Regular}}] \tikzstyle{fileText} = [font={\fontspec[Scale=1]{InconsolataSemiCondensed-Regular}}] \definecolor{color_workspace}{rgb}{0.12,0.6,0.51}\definecolor{color_index}{rgb}{0.78,0.86,0.27}\definecolor{color_local}{rgb}{0.9,0.9,0.2}\definecolor{color_remote}{rgb}{1,0.55,0.15}\definecolor{color_master}{rgb}{0.36,0.27,0.87}\definecolor{color_head}{HTML}{6495ED} %\definecolor{color_head}{rgb}{0.26,0.65,0.91}% A template for making the storage symbol\newcommand{\state}[3]{\draw (#1) node [draw=none,fill=#2,shape=circle,minimum width=2cm] (#3) {\begin{tikzpicture}\node [draw=white, fill=white,shape=cylinder,shape aspect=1.3 ,shape border rotate=90,minimum height=1.6cm,minimum width=1.5cm] at (0,0) (Cylinder) {};\draw[draw=#2,very thick,line width=0.1cm,anchor=north west] ($(Cylinder.north west) +(-0.05cm,-0.1cm)$) arc (-180:0:0.8cm and 0.2cm); \draw[draw=#2,very thick,line width=0.1cm,anchor=north west] ($(Cylinder.north west) +(-0.05cm,-0.5cm)$) arc (-180:0:0.8cm and 0.2cm); \draw[draw=#2,very thick,line width=0.1cm,anchor=north west] ($(Cylinder.north west) +(-0.05cm,-0.9cm)$) arc (-180:0:0.8cm and 0.2cm); \end{tikzpicture}};}% Define dirtree\makeatletter\newcount\dirtree@lvl\newcount\dirtree@plvl\newcount\dirtree@clvl\def\dirtree@growth{%\ifnum\tikznumberofcurrentchild=1\relax\global\advance\dirtree@plvl by 1\expandafter\xdef\csname dirtree@p@\the\dirtree@plvl\endcsname{\the\dirtree@lvl}\fi\global\advance\dirtree@lvl by 1\relax\dirtree@clvl=\dirtree@lvl\advance\dirtree@clvl by -\csname dirtree@p@\the\dirtree@plvl\endcsname\pgf@xa=0.25cm\relax\pgf@ya=-0.5cm\relax\pgf@ya=\dirtree@clvl\pgf@ya\pgftransformshift{\pgfqpoint{\the\pgf@xa}{\the\pgf@ya}}%\ifnum\tikznumberofcurrentchild=\tikznumberofchildren\global\advance\dirtree@plvl by -1\fi}\tikzset{dirtree/.style={growth function=\dirtree@growth,every node/.style={anchor=north},every child node/.style={anchor=west},edge from parent path={(\tikzparentnode\tikzparentanchor) |- (\tikzchildnode\tikzchildanchor)}}}\makeatother\newcommand{\file}[3] {\coordinate (#3) at (#1);\draw [anchor=top left](#1) rectangle ++(1.5,-2);\draw [fill=color_workspace]($(#1) +(1.5,0)$) -- ++(0,-0.5) --++(-0.5,0.5) -- cycle; \node [anchor=north west,fileText] at ($(#1) +(0,-0.5)$) {#2};}\begin{tikzpicture}\state{0,0}{color_workspace}{W}\node[TARGET,fill=white] at ($(W.north) +(0,0.5cm)$) {Workspace};\state{6,0}{color_index}{I}\node[TARGET,fill=white] at ($(I.north) +(0,0.5cm)$) {Staging Area};\state{12,0}{color_local}{L}\node[TARGET,fill=white] at ($(L.north) +(0,0.5cm)$) {Local Repository};\draw[{Round Cap[length=0.5em]}-Triangle Cap,very thick, line width=1cm, draw=color_index] ($(W.east) + (0.1cm,0)$) -- ($(I.west) + (-0.1cm,0)$) node[anchor=center,pos=0.5, text=black,align=center,CODE] {add};\draw[{Round Cap[length=0.5em]}-Triangle Cap,very thick, line width=1cm, draw=color_local] ($(I.east) + (0.1cm,0)$) -- ($(L.west) + (-0.1cm,0)$) node[anchor=center,pos=0.5, text=black,align=center,CODE] {commit};\node [anchor=north west] at ($(W) +(-1cm,-1cm)$) (W0) {\begin{tikzpicture}[dirtree,TREE]\node {} child {node {file 2}}child { node {file 1}};\end{tikzpicture}};%\draw[decorate,decoration={brace,amplitude=5pt},very thick] ($(W0.north) + (-1cm,-1cm)$) -- ($(W0.south) + (-1cm,0.2cm)$);\node [anchor=north west] at ($(I) +(-1cm,-1cm)$) (W0) {\begin{tikzpicture}[dirtree,TREE,text=gray,color=gray]\node {} child {node {file 2}}child { node {file 1}};\end{tikzpicture}};\node [anchor=north west] at ($(L) +(-1cm,-1cm)$) (L0) {\begin{tikzpicture}[dirtree,TREE]\node {} child {node {file 2}}child { node {file 1}};\end{tikzpicture}};\draw[decorate,decoration={brace,amplitude=5pt},very thick] ($(L0.north) + (1.3cm,-0.4cm)$) -- ($(L0.south) + (1.3cm,0.2cm)$);\node [TREE,anchor=west] at ($(L0) +(1.5,-0.1)$) {committed snapshot 1}; \end{tikzpicture}```Now if we add another file (`file 3`) to our_workspace_, add this file to the _staging area_ and thencommit the change, the resulting committed snapshot in the _localrepository_ will resemble the _workspace_. Note, although the_staging area_ contains all three files, only `file 3`points to any new internal content - since `file 1` and`file 2` have unmodified, their instances in the _stagingarea_ point to the same instances as previous. Similarly, thesecond commit in the _Local repository_ will point to one newrepresentation (associated with `file 3`) and two previousrepresentations (associated with `file 1` and `file2`).```{tikz}%| label: Fig14%| engine: tikz%| echo: false%| cache: true%| class: tikz%| engine-opts:%| template: "resources/tikz-minimal.tex"\usetikzlibrary{shapes,arrows,shadows,positioning,mindmap,backgrounds,decorations, calc,fit, decorations.pathreplacing,decorations.pathmorphing, shadings,shapes.geometric,patterns} \usetikzlibrary{arrows.meta}\tikzstyle{TARGET} = [font={\fontspec[Scale=2]{NotoSans-Regular}}] \tikzstyle{CODE} = [font={\fontspec[Scale=2]{InconsolataSemiCondensed-Regular}}]\tikzstyle{TREE} = [font={\fontspec[Scale=1.5]{InconsolataSemiCondensed-Regular}}] \tikzstyle{fileText} = [font={\fontspec[Scale=1]{InconsolataSemiCondensed-Regular}}] \definecolor{color_workspace}{rgb}{0.12,0.6,0.51}\definecolor{color_index}{rgb}{0.78,0.86,0.27}\definecolor{color_local}{rgb}{0.9,0.9,0.2}\definecolor{color_remote}{rgb}{1,0.55,0.15}\definecolor{color_master}{rgb}{0.36,0.27,0.87}\definecolor{color_head}{HTML}{6495ED} %\definecolor{color_head}{rgb}{0.26,0.65,0.91}% A template for making the storage symbol\newcommand{\state}[3]{\draw (#1) node [draw=none,fill=#2,shape=circle,minimum width=2cm] (#3) {\begin{tikzpicture}\node [draw=white, fill=white,shape=cylinder,shape aspect=1.3 ,shape border rotate=90,minimum height=1.6cm,minimum width=1.5cm] at (0,0) (Cylinder) {}; \draw[draw=#2,very thick,line width=0.1cm,anchor=north west] ($(Cylinder.north west) +(-0.05cm,-0.1cm)$) arc (-180:0:0.8cm and 0.2cm); \draw[draw=#2,very thick,line width=0.1cm,anchor=north west] ($(Cylinder.north west) +(-0.05cm,-0.5cm)$) arc (-180:0:0.8cm and 0.2cm); \draw[draw=#2,very thick,line width=0.1cm,anchor=north west] ($(Cylinder.north west) +(-0.05cm,-0.9cm)$) arc (-180:0:0.8cm and 0.2cm); \end{tikzpicture}};}% Define dirtree\makeatletter\newcount\dirtree@lvl\newcount\dirtree@plvl\newcount\dirtree@clvl\def\dirtree@growth{%\ifnum\tikznumberofcurrentchild=1\relax\global\advance\dirtree@plvl by 1\expandafter\xdef\csname dirtree@p@\the\dirtree@plvl\endcsname{\the\dirtree@lvl}\fi\global\advance\dirtree@lvl by 1\relax\dirtree@clvl=\dirtree@lvl\advance\dirtree@clvl by -\csname dirtree@p@\the\dirtree@plvl\endcsname\pgf@xa=0.25cm\relax\pgf@ya=-0.5cm\relax\pgf@ya=\dirtree@clvl\pgf@ya\pgftransformshift{\pgfqpoint{\the\pgf@xa}{\the\pgf@ya}}%\ifnum\tikznumberofcurrentchild=\tikznumberofchildren\global\advance\dirtree@plvl by -1\fi}\tikzset{dirtree/.style={growth function=\dirtree@growth,every node/.style={anchor=north},every child node/.style={anchor=west},edge from parent path={(\tikzparentnode\tikzparentanchor) |- (\tikzchildnode\tikzchildanchor)}}}\makeatother\newcommand{\file}[3] {\coordinate (#3) at (#1);\draw [anchor=top left](#1) rectangle ++(1.5,-2);\draw [fill=color_workspace]($(#1) +(1.5,0)$) -- ++(0,-0.5) --++(-0.5,0.5) -- cycle; \node [anchor=north west,fileText] at ($(#1) +(0,-0.5)$) {#2};}\begin{tikzpicture}\state{0,0}{color_workspace}{W}\node[TARGET,fill=white] at ($(W.north) +(0,0.5cm)$) {Workspace};\state{6,0}{color_index}{I}\node[TARGET,fill=white] at ($(I.north) +(0,0.5cm)$) {Staging Area};\state{12,0}{color_local}{L}\node[TARGET,fill=white] at ($(L.north) +(0,0.5cm)$) {Local Repository};\draw[{Round Cap[length=0.5em]}-Triangle Cap,very thick, line width=1cm, draw=color_index] ($(W.east) + (0.1cm,0)$) -- ($(I.west) + (-0.1cm,0)$) node[anchor=center,pos=0.5, text=black,align=center,CODE] {add};\draw[{Round Cap[length=0.5em]}-Triangle Cap,very thick, line width=1cm, draw=color_local] ($(I.east) + (0.1cm,0)$) -- ($(L.west) + (-0.1cm,0)$) node[anchor=center,pos=0.5, text=black,align=center,CODE] {commit};\node [anchor=north west] at ($(W) +(-1cm,-1cm)$) (W0) {\begin{tikzpicture}[dirtree,TREE]\node {} child { node {file 3}}child [text=color_workspace]{node {file 2}}child [text=color_workspace]{ node {file 1}};\end{tikzpicture}};%\draw[decorate,decoration={brace,amplitude=5pt},very thick] ($(W0.north) + (-1cm,-1cm)$) -- ($(W0.south) + (-1cm,0.2cm)$);\node [anchor=north west] at ($(I) +(-1cm,-1cm)$) (W0) {\begin{tikzpicture}[dirtree,TREE,color=gray,text=gray]\node {} child { node {file 3}}child {node {file 2}}child {node {file 1}};\end{tikzpicture}};\node [anchor=north west] at ($(L) +(-1cm,-1cm)$) (L0) {\begin{tikzpicture}[dirtree,TREE]\node {} child { node {file 3}}child {node {file 2}}child { node {file 1}};\end{tikzpicture}};\draw[decorate,decoration={brace,amplitude=5pt},very thick] ($(L0.north) + (1.3cm,-0.4cm)$) -- ($(L0.south) + (1.3cm,0.2cm)$);\node [TREE,anchor=west] at ($(L0) +(1.5,-0.1)$) {committed snapshot 2}; \node [anchor=north west] at ($(L0) +(-1.2cm,-1cm)$) (L1) {\begin{tikzpicture}[dirtree,TREE]\node {} child {node {file 2}}child { node {file 1}};\end{tikzpicture}};\draw[decorate,decoration={brace,amplitude=5pt},very thick] ($(L1.north) + (1.3cm,-0.4cm)$) -- ($(L1.south) + (1.3cm,0.2cm)$);\node [TREE,anchor=west] at ($(L1) +(1.5,-0.1)$) {committed snapshot 1}; \end{tikzpicture}```Initially, it might seem that there is an awful lot of duplicationgoing on. For example, if we make a minor alteration to a file, whynot just commit the change (delta) instead of an entirely new copy?Well, periodically, git will perform **garbage collection** on therepository. This process **repacks** the objects together into asingle object that comprises only the original blobs and theirsubsequent deltas - thereby gaining efficiency. The process of garbagecollection can also be forced at any time via:```{bash}#| label: gitgc#| echo: true#| eval: false#| classes: bash#| highlight-style: zenburngit gc```During the evolution of most projects, situations arise in which wewish to start work on new components or features that might representa substantial deviation from the main line of evolution. Often, wewould very much like to be able to quarantine the main thread of theproject from these new developments. For example, we may wish to beable to continue tweaking the main project files (in order to addressminor issues and bugs), while at the same time, performing major editsthat take the project in a different direction.This is called _branching_. The main evolutionary thread of theproject is referred to as the **main** _branch_. Deviationsfrom the _main branch_ are generally called **branches** andcan be given any name (other than 'main' or 'HEAD'). For example, wecould start a new _branch_ called 'Feature' where we can evolvethe project in one direction whilst still being able to activelydevelop the _main branch_ at the same time. 'Feature' and'main' _branches_ are depicted in the left hand sequence ofcircles of the schematic below.```{tikz}%| label: Fig-overview%| engine: tikz%| echo: false%| cache: true%| dependson: common%| class: tikz%| engine-opts:%| template: "resources/tikz-minimal.tex"\input{resources/common.tikz}\tikzstyle{TARGET} = [font={\fontspec[Scale=2]{NotoSans-Regular}}]\tikzstyle{refText} = [font={\fontspec[Scale=1.5]{InconsolataSemiCondensed-Regular}}]\begin{tikzpicture}\commit{}{A}{color_inactive}{}{}\commit{right = 1cm of A}{B}{color_inactive}{}{}\commit{right = 1cm of B}{C}{color_commit}{}{}\draw [-,line width=3pt,draw=black!60] (A) -- ++(-1,0);\draw [-,line width=3pt,draw=black!60] (B) -- (A);\draw [-,line width=3pt,draw=black!60] (C) -- (B);\commit{above = 0.5cm of B}{D}{color_inactive}{}{}\draw [-,line width=3pt,draw=black!60] (A.east) to[out=0,in=180] (D);\master{right = 0.5cm of C}\draw[->,line width=3pt,draw=black!60] (master) -- (C);\HEAD{right = 0.5cm of master}\draw[->,line width=3pt,draw=black!60] (HEAD) -- (master);\branch{right = 0.5cm of D}{Feature}\draw[->,line width=3pt,draw=black!60] (Feature) -- (D);\rcommit{right = 3cm of HEAD}{rA}{color_inactive}{}{}\rcommit{right = 1cm of rA}{rB}{color_inactive}{}{}\rcommit{right = 1cm of rB}{rC}{color_inactive}{}{}\rcommit{right = 1cm of rC}{rC2}{color_commit}{}{}\draw [-,line width=3pt,draw=black!60] (rA) -- ++(-1,0);\draw [-,line width=3pt,draw=black!60] (rB) -- (rA);\draw [-,line width=3pt,draw=black!60] (rC) -- (rB);\draw [-,line width=3pt,draw=black!60] (rC2) -- (rC);\rcommit{above = 0.5cm of rB}{rD}{color_inactive}{}{}\draw [-,line width=3pt,draw=black!60] (rA.east) to[out=0,in=180] (rD);\rmaster{right = 0.5cm of rC2}\draw[->,line width=3pt,draw=black!60] (rmaster) -- (rC2);\branch{right = 0.5cm of rD}{origin/Feature}\draw[->,line width=3pt,draw=black!60] (origin/Feature) -- (rD);\rcommit{below = 0.5cm of rB}{rE}{color_inactive}{}{}\draw [-,line width=3pt,draw=black!60] (rA.east) to[out=0,in=180] (rE);\branch{right = 0.5cm of rE}{origin/dev}\draw[->,line width=3pt,draw=black!60] (origin/dev) -- (rE);\rHEAD{right = 0.5cm of rmaster}\draw[->,line width=3pt,draw=black!60] (rHEAD) -- (rmaster);\state{$(A) +(0,3cm)$}{color_local}{L}\node[TARGET,fill=white] at ($(L.north) +(0,0.5cm)$) {Local Repository};\state{$(rA) +(0,3cm)$}{color_remote}{R}\node[TARGET,fill=white] at ($(R.north) +(0,0.5cm)$) {Remote Repository};\end{tikzpicture}```The circles represent **commits** (stored snapshots). We can see thatthe first commit is the common ancestor of the 'Feature' and 'main'_branch_. **HEAD** is a special reference that points to the _tip_ ofthe currently active _commit_. It indicates where the next _commit_will be built onto. In diagram above, `HEAD` is pointing to the last_commit_ in `main`. Hence the next _commit_ will build on this_commit_. To develop the `Feature` _branch_ further, we first have tomove `HEAD` to the tip of the `Feature` _branch_.We can later `merge` the `Feature` _branch_ into the `main` _branch_in order to make the new changes mainstream.To support collaboration, there can also be a _remote repository_(referred to as **origin** and depicted by the squares in the figureabove). Unlike a _local repository_, a _remote repository_ does notcontain a _workspace_ as files are not directly edited in the _remoterepository_. Instead, the _remote repository_ acts as a permanentlyavailable conduit between multiple contributors.In the diagram above, we can see that the _remote repository_(`origin`) has an additional _branch_ (in this called `dev`). Thecollaborator whose _local repository_ is depicted above has either notyet obtained (**pulled**) this _branch_ or has elected not to (asperhaps it is not a direction that they are involved in).We also see that the `main` _branch_ on the _remote repository_ has anewer (additional) _commit_ than the _local repository_.Prior to working on _branch_ a collaborator should first get anyupdates to the _remote repository_. This is a two step process.Firstly, the collaborator **fetches** any changes and then secondly**merges** those changes into their version of the _branch_.Collectively, these two actions are called a **pull**.To make local changes available to others, the collaborator can**push** _commits_ up to the _remote repository_. The _pushed_ changesare applied directly to the nominated _branch_ so it is the usersresponsibility to ensure as much as possible, their local repositoryalready included the most recent _remote repository_ changes (byalways _pulling_ before _pushing_).```{tikz}%| label: Fig-git%| engine: tikz%| echo: false%| cache: true%| dependson: common%| class: tikz%| engine-opts:%| template: "resources/tikz-minimal.tex"\input{resources/common.tikz}\usetikzlibrary{arrows.meta}\tikzstyle{CODE} = [font={\fontspec[Scale=2]{InconsolataSemiCondensed-Regular}}] \tikzstyle{TARGET} = [font={\fontspec[Scale=2]{NotoSans-Regular}}]\tikzstyle{refText} = [font={\fontspec[Scale=1.5]{InconsolataSemiCondensed-Regular}}]\begin{tikzpicture}\coordinate (R1) at (0,8cm);\coordinate (R2) at (0,6cm);\coordinate (R3) at (0,4cm);\coordinate (R4) at (0,2cm);\coordinate (R5) at (0,0cm);\coordinate (R6) at (0,-3cm);\coordinate (R7) at (0,-6cm);\coordinate (R8) at (0,-6cm);\coordinate (R8) at (0,-8cm);\coordinate (R9) at (0,-10cm);\coordinate (R10) at (0,-12cm);\coordinate (R11) at (0,-14cm);\coordinate (C1) at (0cm,-2cm);\coordinate (C2) at (8cm,-2cm);\coordinate (C3) at (16cm,-2cm);\coordinate (C4) at (24cm,-2cm);\definecolor{color_workspace}{rgb}{0.12,0.6,0.51}\definecolor{color_index}{rgb}{0.78,0.86,0.27}\definecolor{color_local}{rgb}{0.9,0.9,0.2}\definecolor{color_remote}{rgb}{1,0.55,0.15}\draw [line width=0.1cm,draw=color_workspace] (C1.west |- R1.north) -- (C1.west |- R11.south); \node [draw=none,fill=color_workspace,shape=circle,minimum width=2cm] at (C1) (W) {\begin{tikzpicture}\node [draw=white, fill=white,shape=cylinder,shape aspect=1.3 ,shape border rotate=90,minimum height=1.6cm,minimum width=1.5cm] at (0,0) (Cylinder) {};\draw[draw=color_workspace,very thick,line width=0.1cm,anchor=north west] ($(Cylinder.north west) +(-0.05cm,-0.1cm)$) arc (-180:0:0.8cm and 0.2cm); \draw[draw=color_workspace,very thick,line width=0.1cm,anchor=north west] ($(Cylinder.north west) +(-0.05cm,-0.5cm)$) arc (-180:0:0.8cm and 0.2cm); \draw[draw=color_workspace,very thick,line width=0.1cm,anchor=north west] ($(Cylinder.north west) +(-0.05cm,-0.9cm)$) arc (-180:0:0.8cm and 0.2cm); \end{tikzpicture} };\node[TARGET,fill=white] at ($(W.south) +(0,-0.5cm)$) {Workspace};\draw [line width=0.1cm,draw=color_index] (C2.west |- R1.north) -- (C2.west |- R11.south); \node [draw=none,fill=color_index,shape=circle,minimum width=2cm] at (C2) (I) {\begin{tikzpicture}\node [draw=white, fill=white,shape=cylinder,shape aspect=1.3 ,shape border rotate=90,minimum height=1.6cm,minimum width=1.5cm] at (0,0) (Cylinder) {};\draw[draw=color_index,very thick,line width=0.1cm,anchor=north west] ($(Cylinder.north west) +(-0.05cm,-0.1cm)$) arc (-180:0:0.8cm and 0.2cm); \draw[draw=color_index,very thick,line width=0.1cm,anchor=north west] ($(Cylinder.north west) +(-0.05cm,-0.5cm)$) arc (-180:0:0.8cm and 0.2cm); \draw[draw=color_index,very thick,line width=0.1cm,anchor=north west] ($(Cylinder.north west) +(-0.05cm,-0.9cm)$) arc (-180:0:0.8cm and 0.2cm); \end{tikzpicture} };\node[TARGET,fill=white] at ($(I.south) +(0,-0.5cm)$) {Staging area (Index)};\draw [line width=0.1cm,draw=color_local] (C3.west |- R1.north) -- (C3.west |- R11.south);\node [draw=none,fill=color_local,shape=circle,minimum width=2cm] at (C3) (L) {\begin{tikzpicture}\node [draw=white, fill=white,shape=cylinder,shape aspect=1.3 ,shape border rotate=90,minimum height=1.6cm,minimum width=1.5cm] at (0,0) (Cylinder) {};\draw[draw=color_local,very thick,line width=0.1cm,anchor=north west] ($(Cylinder.north west) +(-0.05cm,-0.1cm)$) arc (-180:0:0.8cm and 0.2cm); \draw[draw=color_local,very thick,line width=0.1cm,anchor=north west] ($(Cylinder.north west) +(-0.05cm,-0.5cm)$) arc (-180:0:0.8cm and 0.2cm); \draw[draw=color_local,very thick,line width=0.1cm,anchor=north west] ($(Cylinder.north west) +(-0.05cm,-0.9cm)$) arc (-180:0:0.8cm and 0.2cm); \end{tikzpicture} };\node[TARGET,fill=white] at ($(L.south) +(0,-0.5cm)$) {Local Repository};\draw [line width=0.1cm,draw=color_remote] (C4.west |- R1.north) -- (C4.west |- R11.south);\node [draw=none,fill=color_remote,shape=circle,minimum width=2cm] at (C4) (R) {\begin{tikzpicture}\node [draw=white, fill=white,shape=cylinder,shape aspect=1.3 ,shape border rotate=90,minimum height=1.6cm,minimum width=1.5cm] at (0,0) (Cylinder) {};\draw[draw=color_remote,very thick,line width=0.1cm,anchor=north west] ($(Cylinder.north west) +(-0.05cm,-0.1cm)$) arc (-180:0:0.8cm and 0.2cm); \draw[draw=color_remote,very thick,line width=0.1cm,anchor=north west] ($(Cylinder.north west) +(-0.05cm,-0.5cm)$) arc (-180:0:0.8cm and 0.2cm); \draw[draw=color_remote,very thick,line width=0.1cm,anchor=north west] ($(Cylinder.north west) +(-0.05cm,-0.9cm)$) arc (-180:0:0.8cm and 0.2cm); \end{tikzpicture} };\node[TARGET,fill=white] at ($(R.south) +(0,-0.5cm)$) {Remote Repository};\draw[{Round Cap[length=0.5em]}-Triangle Cap,very thick, line width=1cm, draw=color_index] ($(C1.west |- R2.south) + (0.1cm,0)$) -- ($(C2.west |- R2.south) + (-0.1cm,0)$) node[anchor=west,pos=0, text=black,align=center,CODE] {git rm / git mv};\draw[{Round Cap[length=0.5em]}-Triangle Cap,very thick, line width=1cm, draw=color_index] ($(C1.west |- R3.south) + (0.1cm,0)$) -- ($(C2.west |- R3.south) + (-0.1cm,0)$) node[anchor=west,pos=0, text=black,align=center,CODE] {git add};\draw[{Round Cap[length=0.5em]}-Triangle Cap,very thick, line width=1cm, draw=color_local] ($(C2.west |- R3.south) + (0.1cm,0)$) -- ($(C3.west |- R3.south) + (-0.1cm,0)$) node[anchor=west,pos=0, text=black,align=center,CODE] {git commit};\draw[{Round Cap[length=0.5em]}-Triangle Cap,very thick, line width=1cm, draw=color_remote] ($(C3.west |- R3.south) + (0.1cm,0)$) -- ($(C4.west |- R3.south) + (-0.1cm,0)$) node[anchor=west,pos=0, text=black,align=center,CODE] {git push};\draw[{Round Cap[length=0.5em]}-Triangle Cap,very thick, line width=1cm, draw=color_remote] ($(C4.west |- R7.south) + (-0.1cm,0)$) -- ($(C1.west |- R7.south) + (0.1cm,0)$) node[anchor=east,pos=0, text=black,CODE] {git pull / git reset --hard <remote/branch>};\draw[{Round Cap[length=0.5em]}-Triangle Cap,very thick, line width=1cm, draw=color_remote] ($(C4.west |- R8.south) + (-0.1cm,0)$) -- ($(C3.west |- R8.south) + (0.1cm,0)$) node[anchor=east,pos=0, text=black,CODE] {git fetch};\draw[{Round Cap[length=0.5em]}-Triangle Cap,very thick, line width=1cm, draw=color_local] ($(C3.west |- R8.south) + (-0.1cm,0)$) -- ($(C1.west |- R8.south) + (0.1cm,0)$) node[anchor=east,pos=0, text=black,CODE] {git merge / git rebase};\draw[{Round Cap[length=0.5em]}-Triangle Cap,very thick, line width=1cm, draw=color_workspace] ($(C3.west |- R9.south) + (-0.1cm,0)$) -- ($(C1.west |- R9.south) + (0.1cm,0)$) node[anchor=east,pos=0, text=black,CODE] {git checkout HEAD / git reset --hard};\draw[{Round Cap[length=0.5em]}-Triangle Cap,very thick, line width=1cm, draw=color_index] ($(C3.west |- R10.south) + (-0.1cm,0)$) -- ($(C2.west |- R10.south) + (0.1cm,0)$) node[anchor=east,pos=0, text=black,CODE] {git reset --soft};\draw[{Round Cap[length=0.5em]}-Triangle Cap,very thick, line width=1cm, draw=color_workspace] ($(C2.west |- R10.south) + (-0.1cm,0)$) -- ($(C1.west |- R10.south) + (0.1cm,0)$) node[anchor=east,pos=0, text=black,CODE] {git checkout};\draw[Triangle Cap-Triangle Cap,very thick, line width=1cm, draw=color_index!40] ($(C2.west |- R4.south) + (-0.1cm,0)$) -- ($(C1.west |- R4.south) + (0.1cm,0)$) node[anchor=center,pos=0.5, text=black,CODE] {git diff};\draw[Triangle Cap-Triangle Cap,very thick, line width=1cm, draw=color_local!40] ($(C3.west |- R5.south) + (-0.1cm,0)$) -- ($(C1.west |- R5.south) + (0.1cm,0)$) node[anchor=center,pos=0.5, text=black,CODE] {git diff HEAD};\node[rounded corners,CODE,fill=color_workspace,minimum height=1cm] at ($(R1) +(0,1.5cm)$) (init) {git init};\draw[line width=1cm,draw=color_workspace,-{Triangle Cap[cap angle=60,length=0.3cm]}] ($(init.south) +(0,-0.3cm)$) -- +(0,-0.5cm);\node[rounded corners,CODE,fill=color_remote,minimum height=1cm] at ($(C4 |- R1) +(0,1.5cm)$) (initbare) {git init --bare};\draw[line width=1cm,draw=color_remote,-{Triangle Cap[cap angle=60,length=0.3cm]}] ($(initbare.south) +(0,-0.3cm)$) -- +(0,-0.5cm);\end{tikzpicture}```# Installation::: panel-tabset ## WindowsGit Bash (Command Line Version):1. Download the Git for Windows installer from [Git for Windows](https://gitforwindows.org/) - Click the Download button - Select the latest version from the list of `Assets`2. Run the installer and follow the installation prompts.3. Choose the default options unless you have specific preferences.4. Select the default text editor (usually Vim) or choose another editor like Nano or Notepad++.5. Choose to use Git from the Windows Command Prompt (recommended).6. Complete the installation.## MacOSxUsing Homebrew:1. Open Terminal.2. Install Homebrew if not installed::::: {.indented}```{bash}#| label: install1#| echo: true#| eval: false#| cache: false#| engine: bash#| classes: bash/bin/bash-c"$(curl-fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"```:::3. Install Git using Homebrew::::: {.indented}```{bash}#| label: install2#| echo: true#| eval: false#| cache: false#| engine: bash#| classes: bashbrew install git```::::## Linux1. Open Terminal.:::: {.indented}Ubuntu/Debian:```{bash}#| label: install3a#| echo: true#| eval: false#| cache: false#| engine: bash#| classes: bashsudo apt updatesudo apt install git```:::::::: {.indented}Fedora:```{bash}#| label: install3b#| echo: true#| eval: false#| cache: false#| engine: bash#| classes: bashsudo dnf install git```:::::::: {.indented}Arch Linux:```{bash}#| label: install3c#| echo: true#| eval: false#| cache: false#| engine: bash#| classes: bashsudo pacman -S git```:::::::: {.indented}Linux (Red Hat/CentOS):```{bash}#| label: install3d#| echo: true#| eval: false#| cache: false#| engine: bash#| classes: bashsudo yum install git```:::::::To verify that the software is installed and accessible, open aterminal and issue the following:```{bash}#| label: install4a#| echo: true#| eval: true#| cache: false#| engine: bash#| classes: bashgit--version```::: {.callout-tip collapse="true"}## Unsure how to open a terminal?**Windows:**On Windows, you can access a terminal via one of the following: - via the command Prompt: - Press `Win + R` to open the Run dialog. - Type `cmd` and press `Enter`.- via PowerShell: - Press `Win + X` and select "Windows PowerShell."- Git Bash (Optional): - if Git is installed (which we are hoping it is!), open "Git Bash" for a Unix-like terminal experience.**MacOS:**- via Terminal: - Press `Cmd + Space` to open Spotlight. - Type `terminal` and press `Enter`.**Linux:**Oh please. You cannot seriously tell me that you are using Linux anddon't know how to access a terminal.:::In the command above, pay particular attention to the number ofhyphens in the above command - there are two in a row and no spacesbetween the `--` and the word `version`.If you get output similar to above (an indication of what version ofgit you have on your system), then it is likely to be properlyinstalled. If instead you get an error message, then it is likely thatgit is not properly installed and you should try again.# Getting startedBefore using git, it is a good idea to define some global (applied toall your gits) settings. These include your name and email address andwhilst not essential, they are applied to all actions you perform sothe it is easier for others to track the route of changes etc.```{bash}#| label: git-config#| echo: true#| eval: false#| cache: false#| classes: bash#| engine: bashgit config --global user.name "Your Name"git config --global user.email "your_email@whatever.com"```::: {.callout-note}In the above, you should replace "Your Name" with your actual name.This need not be a username (or even a real name) it is not crossreferenced anywhere. It is simply to use in collaboration so that yourcollaborators know who is responsible for your commits.Similarly, you should replace "your_email@whatever.com" with an emailthat you are likely to monitor. This need not be the same emailaddress you have used to register a Github account etc, it is just sothat collaborators have a way of contacting you.:::The remaining sections go through the major git versioning concepts.As previously indicated, git is a command driven program (technicallya family of programs). Nevertheless, many other applications (such asRStudio) are able to interface directly with git for some of the morecommonly used features. Hence, in addition to providing the commandline syntax for performing each task, where possible, this tutorialwill also provide instructions (with screen captures) for RStudio andemacs.# Setting up (initializing) a new repositoryFor the purpose of this tutorial, I will create a temporary folder the`tmp` _folder_ of my `home` _directory_ into which to create andmanipulate repositories. To follow along with this tutorial, you areencouraged to do similarly.## Initialize local repository```{tikz}%| label: Fig1a%| engine: tikz%| echo: false%| cache: true%| dependson: common%| include: false%| class: tikz%| engine-opts:%| template: "resources/tikz-minimal.tex"\input{resources/common.tikz}\tikzstyle{refText} = [font={\fontspec[Scale=1.5]{InconsolataSemiCondensed-Regular}}]\begin{tikzpicture}\commit{}{A}{white}{}{}\draw [-,line width=3pt,draw=black!60] (A) -- ++(-1,0);\master{right = 0.5cm of A}\draw[->,line width=3pt,draw=black!60] (master) -- (A);\HEAD{right = 0.5cm of master}\draw[->,line width=3pt,draw=black!60] (HEAD) -- (master);\end{tikzpicture} ``````{bash}#| label: Fig1a-conv#| cache: false#| echo: falseconvert-trim +repage -density 300 -resize 20% 10_git_files/figure-html/Fig1a-1.pdf 10_git_files/figure-html/Fig1a-1.png ```::: {.panel-tabset}## TerminalWe will start by creating a new directory (folder) which we will call`Repo1` in which to place our repository. All usual directory namingrules apply since it is just a regular directory.```{R}#| label: makedirectory1#| cache: false#| echo: falseif (!dir.exists("~/tmp")) dir.create("~/tmp")unlink('~/tmp/Repo1', recursive=TRUE, force=TRUE)``````{bash}#| label: makedirectory#| echo: true#| cache: false#| engine: bash#| classes: bashmkdir ~/tmp/Repo1```To create (or initialize) a new local repository, issue the `gitinit` _command_ in the root of the working directory youwish to contain the git repository. This can be either an emptydirectory or contain an existing directory/file structure. The`git init` _command_ will add a folder called`.git` to the directory. <b>This is a one timeoperation</b>.```{bash}#| label: git-init#| echo: true#| eval: true#| cache: false#| classes: bash#| engine: bashcd ~/tmp/Repo1git init ```The `.git` _folder_ contains all the necessary_metadata_ to manage the repository.```{bash}#| label: git-initD#| echo: !expr -1#| eval: true#| cache: false#| classes: bash#| engine: bashcd ~/tmp/Repo1 ls-al``````{bash}#| label: git-initD2#| echo: !expr -1#| eval: true#| cache: false#| classes: bash#| engine: bashcd ~/tmp/Repo1 tree-a--charset unicode```config: this file stores settings such as the location of a remote repository that this repository is linked to.description: lists the name (and version) of a repositoryHEAD: lists a reference to the current checked out commit.hooks: a directory containing scripts that are executed at various stages (e.g. `pre-push.sample` is an example of a script executed prior to pushing)info: contains a file `exclude` that lists exclusions (files not to be tracked). This is like `.gitignore`, except is not versioned.objects: this directory contains SHA indexed files being trackedrefs: a master copy of all the repository refslogs: contains a history of each branch## RStudioThe repository that we are going to create in this demonstration couldbe considered to be a new standalone analysis. In Rstudio, this wouldbe considered a **project**. So, we will initialise the git repositorywhile we create a new Rstudio project. To do so:1. click on the `Project` selector in the top right of the Rstudio window (as highlighted by the red ellipse in the image below.{width=100%}2. select `New Project` from the dropdown menu3. select `New Directory` form the Create Project panel4. select `New Project` from the Project Type panel5. Provide a name for the new directory to be created and use the`Browse` button to locate a suitable position for this new directory. **Ensure that the `Create a git repository` checkbox is checked**{width=50%}6. Click the `Create Project` buttonIf successful, you should notice a couple of changes - these arehighlighted in the following figure:{width=60%}- a new `Git` tab will appear in the top right panel- the contents of this newly created project/repository will appear in the `Files` tab of the bottom right panelIf the files and directories that begin with a `.` do not appear,click on the `More file commands` cog and make sure the `Show HiddenFiles` option is ticked.The newly created files/folders are:- `.git` - this directory houses the repository information and should not generally be edited directly- `.gitignore` - this file defines files/folders to be excluded from the repository. We will discuss this file more later- `.Rhistory` - this file will accrue a history of the commands you have evaluated in R within this project- `.Rproj.user` - this folder stores some project-specific temporary files- `Repo1.Rproj` - contains the project specific settings**Note that on the left side of the Rstudio window there are twopanels - one called "Console", the other called "Terminal". Theconsole window is for issuing R commands and the terminal window isfor issuing system (bash, shell) commands. Throughout this tutorial,as an alternative to using the point and click Rstudio methods, youcould instead issue the `Terminal` instructions into the "Terminal"panel. Indeed, there are some git commands that are not supporteddirectly by Rstudio and can only be entered into the terminal**## Emacs (magit):::Note, at this stage, no files are being tracked, that is, they are notpart of the repository.To assist in gaining a greater understanding of the workings of git,we will use a series of schematics diagrams representing the contentsof four important sections of the repository. Typically, these figureswill be contained within callout panels that expand/collapse uponclicking. However, for this first time, they will be standalone.In the first figure below, the left hand panel represents the contentsof the root directory (excluding the `.git` folder) - this is the_workspace_ and is currently empty.The three white panels represent three important parts of the innerstructure of the `.git` folder. A newly initialized repository isrelatively devoid of any specific metadata since there are no stagedor committed files. In the root of the `.git` folder, there is a filecalled `HEAD`.The figure is currently very sparse. However, as the repository grows,so the figure will become more complex.```{tikz}%| label: Fig-advanced1%| engine: tikz%| echo: false%| cache: true%| class: tikz%| engine-opts:%| template: "resources/tikz-minimal.tex"\usetikzlibrary{arrows.meta}\definecolor{color_workspace}{rgb}{0.12,0.6,0.51}\definecolor{color_tree}{HTML}{9ACD32} %\definecolor{color_tree}{rgb}{0.78,0.86,0.27}\definecolor{color_commit}{rgb}{0.9,0.9,0.2}\definecolor{color_remote}{rgb}{1,0.55,0.15}\definecolor{color_master}{rgb}{0.36,0.27,0.87}\definecolor{color_head}{HTML}{6495ED}\definecolor{color_index}{HTML}{E0FFFF} %\definecolor{color_index}{rgb}{1,1,1}\definecolor{color_file}{rgb}{0.8,0.8,0.8}\tikzstyle{TARGET} = [font={\fontspec[Scale=2]{NotoSans-Regular}}] \tikzstyle{CODE} = [font={\fontspec[Scale=2]{InconsolataSemiCondensed-Regular}}] \tikzstyle{TREE} = [font={\fontspec[Scale=1.5]{InconsolataSemiCondensed-Regular}}] \tikzstyle{fileText} = [font={\fontspec[Scale=1.1]{InconsolataSemiCondensed-Regular}}] %Define a file \newcommand{\file}[4] {\def\corner{0.15in};\def\cornerradius{0.02in};\def\lwidth{0.02in};\def\h{0.5in};\def\w{0.85in};\def\nline{0};\def\iconmargin{0.1in};\def\topmargin{0.3in};\node at (#1) {\begin{tikzpicture}\coordinate (nw) at ($(-0.05in*1,-0.15in*1)$);\coordinate (#3) at (#1); \coordinate (ne0) at ($(nw) + (\w, 0)$);\coordinate (ne1) at ($(ne0) - (\corner, 0)$);\coordinate (ne2) at ($(ne0) - (0, \corner)$);\coordinate (se) at ($(ne0) + (0, -\h)$); \filldraw [-, line width = \lwidth, fill=#4] (nw) -- (ne1) -- (ne2)[rounded corners=\cornerradius]--(se) -- (nw|-se) -- cycle;\draw [-, line width = \lwidth] (ne1) [rounded corners=\cornerradius]-- (ne1|-ne2) -- (ne2);\node [anchor=north west,TREE] at (nw) {#2};\foreach \k in {0,...,\nline}{\draw [-, line width = \lwidth, line cap=round] ($(nw|-se) + (\iconmargin,\iconmargin) + (0,{(\k-1)/(\nline-1)*(\h - \iconmargin - \topmargin)})$)-- ++ ($(\w,0) - 2*(\iconmargin,0)$);}\end{tikzpicture}};}% end of file definition\begin{tikzpicture}\coordinate (G_ul) at (0,0);\coordinate (G_ll) at ($(G_ul) +(0,-10)$);\coordinate (G_lr) at ($(G_ll) +(4,0)$);\coordinate (G_ur) at ($(G_ul) +(4,0)$);\node[TREE,anchor=west] at ($(G_ul) +(0,-0.5)$) (git) {.git/};\file{$(git.west) +(1.5,-2)$}{HEAD}{HEAD}{color_head}\draw (G_ul) -- (G_ll) -- (G_lr) -- (G_ur) -- cycle;%refs\node[TREE,anchor=west] at ($(G_ul) +(-5,-0.5)$) (git_ref) {.git/refs/};\draw[] ($(G_ul) +(-5,0)$) -- ++(0,-10) -- ++(4.9,0) -- ++(0,10) -- cycle;%objects\node[TREE,anchor=west] at ($(G_ul) +(-17,-0.5)$) (git_object) {.git/objects/};\draw[] ($(G_ul) +(-17,0)$) -- ++(0,-10) -- ++(11.9,0) -- ++(0,10) -- cycle;%files\node[TREE,anchor=west] at ($(G_ul) +(-21,-0.5)$) (root) {/};\begin{pgfonlayer}{background}\draw[fill=color_workspace!20] ($(G_ul) +(-21,0)$) -- ++(0,-10) -- ++(3.9,0) -- ++(0,10) -- cycle;\end{pgfonlayer}\end{tikzpicture}```The second figure provides the same information, yet via a networkdiagram. Again, this will not be overly meaningful until therepository contains some content.```{bash}#| label: gitDraw1#| engine: bash#| echo: false./resources/git-draw--image-only--sha1-length 5 --hide-legend--hide-reflogs--git-dir ~/tmp/Repo1/.git --image-filename 10_git_files/figure-html/drawGit1.png ```## Initializing other types of repositoriesThe above demonstrated how to initialise a new local repository fromscratch. However, there are times when we instead want to:- create a git repository from an existing directory or project- collaborate with someone on an existing repository- create a remote repositoryThese situations are briefly demonstrated in the following sections.### Initializing a shared (remote) repository```{tikz}%| label: Fig1b%| engine: tikz%| echo: false%| cache: true%| dependson: common%| include: false%| class: tikz%| engine-opts:%| template: "resources/tikz-minimal.tex"\input{resources/common.tikz}\tikzstyle{refText} = [font={\fontspec[Scale=1.5]{InconsolataSemiCondensed-Regular}}]\begin{tikzpicture}\rcommit{}{A}{white}{}{}\draw [-,line width=3pt,draw=black!60] (A) -- ++(-1,0);\master{right = 0.5cm of A}\draw[->,line width=3pt,draw=black!60] (master) -- (A);\HEAD{right = 0.5cm of master}\draw[->,line width=3pt,draw=black!60] (HEAD) -- (master);\end{tikzpicture} ``````{bash}#| label: Fig1b-conv#| cache: false#| echo: falseconvert-trim +repage -density 300 -resize 20% 10_git_files/figure-html/Fig1b-1.pdf 10_git_files/figure-html/Fig1b-1.png ```The main repository for sharing should not contain the workingdirectory as such - only the `.git` tree and the`.gitignore` file. Typically the point of a remoterepository is to act as a perminantly available repository from whichmultiple uses can exchange files. Consequently, those accessing thisrepository should only be able to interact with the .git_metadata_ - they do not directly modify any files.Since a remote repository is devode of the working files anddirectories, it is referred to as _bare_. ::: {.panel-tabset}#### TerminalTo create a _bare_ remote repository, issue the `git init --bare`_command_ after logging in to the remote location.```{bash}#| label: git-initB#| echo: true#| eval: false#| cache: false#| classes: bash#| engine: bashgit init --bare```#### RstudioUse the instructions for the `Terminal`:::### Cloning an existing repository```{tikz}%| label: Fig1c%| engine: tikz%| echo: false%| cache: true%| dependson: common%| include: false%| class: tikz%| engine-opts:%| template: "resources/tikz-minimal.tex"\input{resources/common.tikz}\tikzstyle{refText} = [font={\fontspec[Scale=1.5]{InconsolataSemiCondensed-Regular}}]\begin{tikzpicture}\state{0,0}{color_local}{L}\node[TARGET,fill=white] at ($(L.north) +(0,0.5cm)$) {Local Repository};\commit{right = 0.5 cm of L}{A}{color_inactive}{}{}\commit{right = 1cm of A}{B}{color_commit}{}{}\draw [-,line width=3pt,draw=black!60] (A) -- (L.east);\draw [<-,line width=3pt,draw=black!60] (A) -- (B);\master{right = 0.5cm of B}\draw[->,line width=3pt,draw=black!60] (master) -- (B);\HEAD{right = 0.5cm of master}\draw[->,line width=3pt,draw=black!60] (HEAD) -- (master);\state{$(HEAD) +(3,0)$}{color_remote}{R}\node[TARGET,fill=white] at ($(R.north) +(0,0.5cm)$) {Remote Repository};\rcommit{right = 1cm of R}{rA}{color_inactive}{}{}\commit{right = 1cm of rA}{rB}{color_commit}{}{}\draw [-,line width=3pt,draw=black!60] (rA) -- (R.east);\draw [<-,line width=3pt,draw=black!60] (rA) -- (rB);\rmaster{right = 0.5cm of rB}\draw[->,line width=3pt,draw=black!60] (rmaster) -- (rB);\rHEAD{right = 0.5cm of rmaster}\draw[->,line width=3pt,draw=black!60] (rHEAD) -- (rmaster);\draw [->,line width=3pt,draw=black!60] (rB.south west) to [out=220,in=300] (B.south east);\end{tikzpicture} ``````{bash}#| label: Fig1c-conv#| cache: false#| echo: falseconvert-trim +repage -density 300 -resize 20% 10_git_files/figure-html/Fig1c-1.pdf 10_git_files/figure-html/Fig1c-1.png ```To get your own local copy of an existing repository, issue the `gitclone <repourl>` _command_ in the root of the working directory youwish to contain the git repository. The `repo url` points to thelocation of the existing repository to be cloned. This is also a **onetime operation** and should be issued in an otherwise empty directory.The `repo url` can be located on any accessible filesytem (local orremote). The cloning process also stores a link back to the originallocation of the repository (called **origin**). This provides aconvenient way for the system to keep track of where the localrepository should exchange files.Many git repositories are hosted on sites such as github, gitlab orbitbucket. Within an online git repository, these sites provide urllinks for cloning.::: {.panel-tabset}#### Terminal```{bash}#| label: git-clone#| echo: true#| eval: false#| cache: false#| classes: bash#| engine: bashgit clone "url.git"```where `"url.git"` is the url of the hosted repository.#### Rstudio1. click on the `Project` selector in the top right of the Rstudio window (as highlighted by the red ellipse in the image below.2. select `New Project` from the dropdown menu3. select `Version Control` form the Create Project panel4. select `Git` from the Create Project from Version Control panel5. paste in the address of the repository that you want to clone, optionally a name for this repository (if you do not like the original name) and use the `Browse` button to locate a suitable position for this new directory.6. Click the `Create Project` button:::### Initializing a repository in an existing directory::: {.panel-tabset}#### TerminalThis is the same as for a new directory.```{bash}#| label: git-create1a#| echo: true#| eval: false#| cache: false#| classes: bash#| engine: bashgit init```#### Rstudio1. click on the `Project` selector in the top right of the Rstudio window (as highlighted by the red ellipse in the image below.2. select `New Project` from the dropdown menu3. select `Existing Directory` form the Create Project panel4. use the `Browse` button to locate the existing directory6. Click the `Create Project` button:::# Tracking filesThe basic workflow for tracking files is a two step process in whichone or more files are first added to the **staging area** beforethey are committed to the **local repository**. The staging areaacts as a little like a snapshot of what the repository will look likeonce the changes have been committed. The staging area also acts likea buffer between the files in the workspace (actual local copy offiles) and the local repository (committed changes).The reason that this is a two step process is that it allows the userto make edits to numerous files, yet block the commits in smallerchunks to help isolate changes in case there is a need to roll back toprevious versions.## Staging filesWhen a file is first added to the staging area, a full copy of thatfile is added to the staging area (not just the file diffs as in otherversioning systems).::: {.panel-tabset}### TerminalTo demonstrate lets create a file (a simple text file containing thestring saying 'File 1') and add it to the staging area.```{bash}#| label: git-add#| echo: !expr -1#| eval: true#| cache: false#| classes: bash#| engine: bashcd ~/tmp/Repo1echo'File 1'> file1```Now lets add this file to the staging area```{bash}#| label: git-add1#| echo: !expr -1#| eval: true#| cache: false#| classes: bash#| engine: bashcd ~/tmp/Repo1git add file1```To see the status of the repository (that is, what files are beingtracked), we issue the `git status` _command_```{bash}#| label: git-status#| echo: !expr -1#| eval: true#| cache: false#| classes: bash#| engine: bashcd ~/tmp/Repo1git status```This indicates that there is a single file (`file1`) in thestaging area### RstudioTo demonstrate lets create a file (a simple text file containing thestring saying 'File 1') and add it to the staging area.1. Click the green "New File" button followed by the "Text File" option (or click the equivalent option from the "File" menu){width=50%}2. Type `File 1` in the panel with the flashing cursor. This panel represents the contents of the yet to be named file that we are creating.{width=50%}3. Click the "Save" or "Save all" buttons (or select the equivalent items from the "File" menu) and name the file "file1" Switch to the `Git` tab and you should notice a number of items (including the file we just created) in the panel. These are files that git is aware of, but not yet tracking. This panel acts as a status window. The yellow "?" symbol indicates that git considers these files "untracked"{width=50%}4. To stage a file, click on the corresponding checkbox - the status symbol should change to a green "A" (for added){width=50%}:::Our simple overview schematic represents the staging of file 1.```{tikz}%| label: Fig-advanced2a%| engine: tikz%| echo: false%| cache: true%| class: tikz%| engine-opts:%| template: "resources/tikz-minimal.tex"\usetikzlibrary{shapes,arrows,shadows,positioning,mindmap,backgrounds,decorations, calc,fit, decorations.pathreplacing,decorations.pathmorphing, shadings,shapes.geometric,patterns} \usetikzlibrary{arrows.meta}\tikzstyle{TARGET} = [font={\fontspec[Scale=2]{NotoSans-Regular}}] \tikzstyle{CODE} = [font={\fontspec[Scale=2]{InconsolataSemiCondensed-Regular}}] \tikzstyle{TREE} = [font={\fontspec[Scale=1.5]{InconsolataSemiCondensed-Regular}}] \tikzstyle{fileText} = [font={\fontspec[Scale=1.1]{InconsolataSemiCondensed-Regular}}] \definecolor{color_workspace}{rgb}{0.12,0.6,0.51}\definecolor{color_index}{rgb}{0.78,0.86,0.27}\definecolor{color_local}{rgb}{0.9,0.9,0.2}\definecolor{color_remote}{rgb}{1,0.55,0.15}\definecolor{color_master}{rgb}{0.36,0.27,0.87}\definecolor{color_head}{HTML}{6495ED} %\definecolor{color_head}{HTML}{6495ED}% A template for making the storage symbol\newcommand{\state}[3]{\draw (#1) node [draw=none,fill=#2,shape=circle,minimum width=2cm] (#3) {\begin{tikzpicture}\node [draw=white, fill=white,shape=cylinder,shape aspect=1.3 ,shape border rotate=90,minimum height=1.6cm,minimum width=1.5cm] at (0,0) (Cylinder) {}; \draw[draw=#2,very thick,line width=0.1cm,anchor=north west] ($(Cylinder.north west) +(-0.05cm,-0.1cm)$) arc (-180:0:0.8cm and 0.2cm); \draw[draw=#2,very thick,line width=0.1cm,anchor=north west] ($(Cylinder.north west) +(-0.05cm,-0.5cm)$) arc (-180:0:0.8cm and 0.2cm); \draw[draw=#2,very thick,line width=0.1cm,anchor=north west] ($(Cylinder.north west) +(-0.05cm,-0.9cm)$) arc (-180:0:0.8cm and 0.2cm); \end{tikzpicture}};}% Define dirtree\makeatletter\newcount\dirtree@lvl\newcount\dirtree@plvl\newcount\dirtree@clvl\def\dirtree@growth{%\ifnum\tikznumberofcurrentchild=1\relax\global\advance\dirtree@plvl by 1\expandafter\xdef\csname dirtree@p@\the\dirtree@plvl\endcsname{\the\dirtree@lvl}\fi\global\advance\dirtree@lvl by 1\relax\dirtree@clvl=\dirtree@lvl\advance\dirtree@clvl by -\csname dirtree@p@\the\dirtree@plvl\endcsname\pgf@xa=0.25cm\relax\pgf@ya=-0.5cm\relax\pgf@ya=\dirtree@clvl\pgf@ya\pgftransformshift{\pgfqpoint{\the\pgf@xa}{\the\pgf@ya}}%\ifnum\tikznumberofcurrentchild=\tikznumberofchildren\global\advance\dirtree@plvl by -1\fi}\tikzset{dirtree/.style={growth function=\dirtree@growth,every node/.style={anchor=north},every child node/.style={anchor=west},edge from parent path={(\tikzparentnode\tikzparentanchor) |- (\tikzchildnode\tikzchildanchor)}}}\makeatother%end of t%Define a file \newcommand{\file}[3] {\coordinate (#3) at (#1);\draw [anchor=top left](#1) rectangle ++(2,-2);\draw [fill=color_workspace]($(#1) +(2,0)$) -- ++(0,-0.5) --++(-0.5,0.5) -- cycle; \node [anchor=north west,fileText] at ($(#1) +(0.3,-0.3)$) {#2};}% end of file definition\begin{tikzpicture}\state{0,0}{color_workspace}{W}\node[TARGET,fill=white] at ($(W.north) +(0,0.5cm)$) {Workspace};\state{6,0}{color_index}{I}\node[TARGET,fill=white] at ($(I.north) +(0,0.5cm)$) {Staging Area};\state{12,0}{color_local}{L}\node[TARGET,fill=white] at ($(L.north) +(0,0.5cm)$) {Local Repository};\draw[{Round Cap[length=0.5em]}-Triangle Cap,very thick, line width=1cm, draw=color_index] ($(W.east) + (0.1cm,0)$) -- ($(I.west) + (-0.1cm,0)$) node[anchor=center,pos=0.5, text=black,align=center,CODE] {add};\node [anchor=north west] at ($(W) +(-1cm,-1cm)$) (W0) {\begin{tikzpicture}[dirtree,TREE]\node {} child {node {file 1}};\end{tikzpicture}};%\draw[decorate,decoration={brace,amplitude=5pt},very thick] ($(W0.north) + (-1cm,-1cm)$) -- ($(W0.south) + (-1cm,0.2cm)$);\node [anchor=north west] at ($(I) +(-1cm,-1cm)$) (W0) {\begin{tikzpicture}[dirtree,TREE,text=gray,color=gray]\node {} child {node {file 1}};\end{tikzpicture}};\end{tikzpicture} ```A schematic of the internal working of git shows in`.git/objects` a **blob** has been created. This is acompressed version of `file1`. Its filename is a 40 digit**SHA-1 checksum** has representing the contents of the`file1`. To re-iterate, the blob name is a SHA-1 hash ofthe file contents (actually, the first two digits form a folder andthe remaining 38 form the filename).We can look at the contents of this _blob_ using the `gitcat-file` _command_. This command outputs the contents of acompressed _object_ (_blob_, _tree_, _commit_)from either the objects name (or unique fraction thereof) or its_tag_ (we will discuss tags later). ```{bash}#| label: git-blob1#| echo: !expr -1#| eval: true#| cache: false#| classes: bash#| engine: bashcd ~/tmp/Repo1git cat-file blob 50fcd```The add (staging) process also created a `index` file. This filesimply points to the _blob_ that is part of the snapshot. The gitinternals schematic illustrates the internal changes in response tostaging a file.```{cat}#| label: Fig-advanced2#| echo: true#| class: tikz #| engine.opts:#| file: "resources/Fig-advanced2.tikz"\documentclass{minimal}\usepackage[paperwidth=35cm,paperheight=10cm,hmargin=0cm,vmargin=0cm]{geometry}%\usepackage[hmargin=0cm,vmargin=0cm]{geometry}\usepackage{fontspec}\usepackage[xelatex,active,tightpage]{preview}\renewcommand{\baselinestretch}{0.75}\usepackage{tikz}\usetikzlibrary{shapes,arrows,shadows,positioning,mindmap,backgrounds,decorations, calc,fit, decorations.pathreplacing,decorations.pathmorphing, shadings,shapes.geometric,patterns}\begin{document}\include{preview}\begin{preview}\usetikzlibrary{arrows.meta}\definecolor{color_workspace}{rgb}{0.12,0.6,0.51}\definecolor{color_tree}{HTML}{9ACD32}%\definecolor{color_tree}{rgb}{0.78,0.86,0.27}\definecolor{color_commit}{rgb}{0.9,0.9,0.2}\definecolor{color_remote}{rgb}{1,0.55,0.15}\definecolor{color_master}{rgb}{0.36,0.27,0.87}\definecolor{color_head}{HTML}{6495ED}%\definecolor{color_head}{HTML}{6495ED}\definecolor{color_index}{HTML}{E0FFFF}%\definecolor{color_index}{rgb}{1,1,1}\definecolor{color_file}{rgb}{1,1,1}\tikzstyle{TARGET}=[font={\fontspec[Scale=2]{NotoSans-Regular}}]\tikzstyle{CODE}=[font={\fontspec[Scale=2]{InconsolataSemiCondensed-Regular}}]\tikzstyle{TREE}=[font={\fontspec[Scale=1.5]{InconsolataSemiCondensed-Regular}}]\tikzstyle{fileText}=[font={\fontspec[Scale=1.1]{InconsolataSemiCondensed-Regular}}]%Define a file \newcommand{\file}[4]{\def\corner{0.15in};\def\cornerradius{0.02in};\def\lwidth{0.02in};\def\h{0.5in};\def\w{0.85in};\def\nline{0};\def\iconmargin{0.1in};\def\topmargin{0.3in};\node at (#1){\begin{tikzpicture}\coordinate (nw) at ($(-0.05in*1,-0.15in*1)$);\coordinate (#3) at (#1);\coordinate (ne0) at ($(nw)+(\w,0)$);\coordinate (ne1) at ($(ne0)-(\corner,0)$);\coordinate (ne2) at ($(ne0)-(0, \corner)$);\coordinate (se) at ($(ne0)+(0,-\h)$);\filldraw [-, line width = \lwidth, fill=#4](nw)--(ne1)--(ne2)[rounded corners=\cornerradius]--(se)--(nw|-se)-- cycle;\draw [-, line width = \lwidth](ne1)[rounded corners=\cornerradius]--(ne1|-ne2)--(ne2);\node [anchor=north west,TREE] at (nw){#2};\foreach \k in {0,...,\nline}{\draw [-, line width = \lwidth, line cap=round]($(nw|-se)+(\iconmargin,\iconmargin)+(0,{(\k-1)/(\nline-1)*(\h - \iconmargin - \topmargin)})$)--++($(\w,0)-2*(\iconmargin,0)$);}\end{tikzpicture}};}% end of file definition\begin{tikzpicture}\coordinate (G_ul) at (0,0);\coordinate (G_ll) at ($(G_ul)+(0,-10)$);\coordinate (G_lr) at ($(G_ll)+(4,0)$);\coordinate (G_ur) at ($(G_ul)+(4,0)$);\node[TREE,anchor=west] at ($(G_ul)+(0,-0.5)$)(git){.git/};\file{$(git.west)+(1.5,-2)$}{HEAD}{HEAD}{color_head}\file{$(HEAD)+(0,-2)$}{index}{index}{color_index}\draw[](G_ul)--(G_ll)--(G_lr)--(G_ur)-- cycle;%refs\node[TREE,anchor=west] at ($(G_ul)+(-5,-0.5)$)(git_ref){.git/refs/};\draw[]($(G_ul)+(-5,0)$)--++(0,-10)--++(4.9,0)--++(0,10)-- cycle;%objects\node[TREE,anchor=west] at ($(G_ul)+(-17,-0.5)$)(git_object){.git/objects/};\file{$(git_object.west)+(1.5,-2)$}{\textcolor{black}{hashblob}}{blob1}{color_workspace}\draw[]($(G_ul)+(-17,0)$)--++(0,-10)--++(11.9,0)--++(0,10)-- cycle;%trees%commits%files\node[TREE,anchor=west] at ($(G_ul)+(-21,-0.5)$)(root){/};\file{$(root.west)+(1.7,-2)$}{\textcolor{black}{file1}}{file1}{color_file}\draw [very thick](root)--(root |- file1)--++(0.2,0);\begin{pgfonlayer}{background}\draw[fill=color_workspace!20]($(G_ul)+(-21,0)$)--++(0,-10)--++(3.9,0)--++(0,10)-- cycle;\end{pgfonlayer}%arrows\draw[->,very thick,dashed]($(file1)+(1.2,0)$)--($(blob1)+(-1.1,0)$);\draw[->,very thick,solid]($(index)+(-1,0)$)--($(blob1)+(1.2,0)$);\end{tikzpicture}\end{preview}\end{document}``````{r, cache=FALSE, echo=FALSE, results='asis'}library(knitr)hash =system('cd ~/tmp/Repo1; git ls-files --stage', intern=TRUE)hash =read.table(textConnection(hash))hash_blob =strtrim(hash$V2,5)system(paste0("sed -i 's/hashblob/",hash_blob,"/g' resources/Fig-advanced2.tikz"))system("xelatex -output-directory=resources resources/Fig-advanced2.tikz")system("convert +repage -density 300 -resize 20% resources/Fig-advanced2.pdf resources/Fig-advanced2.png")```::: {.callout-note collapse="true"}## Another visual representation of the git```{bash}#| label: gitDraw2#| engine: bash#| echo: false./resources/git-draw--image-only--sha1-length 5 --hide-legend--hide-reflogs--git-dir ~/tmp/Repo1/.git --image-filename 10_git_files/figure-html/drawGit2.png ```:::## Commit to local repository```{tikz}%| label: Fig2a%| engine: tikz%| echo: false%| cache: true%| dependson: common%| include: false%| class: tikz%| engine-opts:%| template: "resources/tikz-minimal.tex"\input{resources/common.tikz}\tikzstyle{refText} = [font={\fontspec[Scale=1.1]{InconsolataSemiCondensed-Regular}}] \begin{tikzpicture}\commit{}{A}{color_commit}{}{}\draw [-,line width=3pt,draw=black!60] (A) -- ++(-1,0);\master{right = 0.5cm of A}\draw[->,line width=3pt,draw=black!60] (master) -- (A);\HEAD{right = 0.5cm of master}\draw[->,line width=3pt,draw=black!60] (HEAD) -- (master);\end{tikzpicture} ``````{bash}#| label: Fig2a-conv#| cache: false#| echo: falseconvert-trim +repage -density 300 -resize 20% 10_git_files/figure-html/Fig2a-1.pdf 10_git_files/figure-html/Fig2a-1.png ```::: {.panel-tabset}### TerminalTo commit a set of changes from the staging area to the localrepository, we issue the `git commit` _command_. We usually add the`-m` _switch_ to explicitly supply a message to be associated with thecommit. This message should ideally describe what the changes thecommit introduces to the repository.```{bash}#| label: git-commit#| echo: !expr -1#| eval: true#| cache: false#| classes: bash#| engine: bashcd ~/tmp/Repo1git commit -m'Initial repo and added file1'```We now see that the status has changed. It indicates that the tree inthe workspace is in sync with the repository.```{bash}#| label: git-commit1#| echo: !expr -1#| eval: true#| cache: false#| classes: bash#| engine: bashcd ~/tmp/Repo1git status```### RstudioTo commit a set of changes from the staging area to the localrepository:1. click on the "Commit" button to open the "Review Changes" window{width=80%} This box will list the files to be committed (in this case "file1"), the changes in this file since the previous commit (as this is the first time this file has been committed, the changes are the file contents)2. you should also provide a commit message (in the figure above, I entered "Initial commit". This message should ideally describe what the changes the commit introduces to the repository.3. click the "Commit" button and you will be presented with a popup message. This message provides feedback to confirm that your commit was successful. 4. close the popup window and the "Review Changes" window`file1` should now have disappeared from the git status panel.:::Our simple overview schematic represents the staging of file 1.```{tikz}%| label: Fig-advanced3a%| engine: tikz%| echo: false%| cache: true%| class: tikz%| engine-opts:%| template: "resources/tikz-minimal.tex"\usetikzlibrary{shapes,arrows,shadows,positioning,mindmap,backgrounds,decorations, calc,fit, decorations.pathreplacing,decorations.pathmorphing, shadings,shapes.geometric,patterns} \usetikzlibrary{arrows.meta}\tikzstyle{TARGET} = [font={\fontspec[Scale=2]{NotoSans-Regular}}] \tikzstyle{CODE} = [font={\fontspec[Scale=2]{InconsolataSemiCondensed-Regular}}] \tikzstyle{TREE} = [font={\fontspec[Scale=1.5]{InconsolataSemiCondensed-Regular}}] \tikzstyle{fileText} = [font={\fontspec[Scale=1.1]{InconsolataSemiCondensed-Regular}}] \definecolor{color_workspace}{rgb}{0.12,0.6,0.51}\definecolor{color_index}{rgb}{0.78,0.86,0.27}\definecolor{color_local}{rgb}{0.9,0.9,0.2}\definecolor{color_remote}{rgb}{1,0.55,0.15}\definecolor{color_master}{rgb}{0.36,0.27,0.87}\definecolor{color_head}{HTML}{6495ED} %\definecolor{color_head}{HTML}{6495ED}% A template for making the storage symbol\newcommand{\state}[3]{\draw (#1) node [draw=none,fill=#2,shape=circle,minimum width=2cm] (#3) {\begin{tikzpicture}\node [draw=white, fill=white,shape=cylinder,shape aspect=1.3 ,shape border rotate=90,minimum height=1.6cm,minimum width=1.5cm] at (0,0) (Cylinder) {}; \draw[draw=#2,very thick,line width=0.1cm,anchor=north west] ($(Cylinder.north west) +(-0.05cm,-0.1cm)$) arc (-180:0:0.8cm and 0.2cm); \draw[draw=#2,very thick,line width=0.1cm,anchor=north west] ($(Cylinder.north west) +(-0.05cm,-0.5cm)$) arc (-180:0:0.8cm and 0.2cm); \draw[draw=#2,very thick,line width=0.1cm,anchor=north west] ($(Cylinder.north west) +(-0.05cm,-0.9cm)$) arc (-180:0:0.8cm and 0.2cm); \end{tikzpicture}};}% Define dirtree\makeatletter\newcount\dirtree@lvl\newcount\dirtree@plvl\newcount\dirtree@clvl\def\dirtree@growth{%\ifnum\tikznumberofcurrentchild=1\relax\global\advance\dirtree@plvl by 1\expandafter\xdef\csname dirtree@p@\the\dirtree@plvl\endcsname{\the\dirtree@lvl}\fi\global\advance\dirtree@lvl by 1\relax\dirtree@clvl=\dirtree@lvl\advance\dirtree@clvl by -\csname dirtree@p@\the\dirtree@plvl\endcsname\pgf@xa=0.25cm\relax\pgf@ya=-0.5cm\relax\pgf@ya=\dirtree@clvl\pgf@ya\pgftransformshift{\pgfqpoint{\the\pgf@xa}{\the\pgf@ya}}%\ifnum\tikznumberofcurrentchild=\tikznumberofchildren\global\advance\dirtree@plvl by -1\fi}\tikzset{dirtree/.style={growth function=\dirtree@growth,every node/.style={anchor=north},every child node/.style={anchor=west},edge from parent path={(\tikzparentnode\tikzparentanchor) |- (\tikzchildnode\tikzchildanchor)}}}\makeatother%end of t%Define a file \newcommand{\file}[3] {\coordinate (#3) at (#1);\draw [anchor=top left](#1) rectangle ++(2,-2);\draw [fill=color_workspace]($(#1) +(2,0)$) -- ++(0,-0.5) --++(-0.5,0.5) -- cycle; \node [anchor=north west,fileText] at ($(#1) +(0.3,-0.3)$) {#2};}% end of file definition\begin{tikzpicture}\state{0,0}{color_workspace}{W}\node[TARGET,fill=white] at ($(W.north) +(0,0.5cm)$) {Workspace};\state{6,0}{color_index}{I}\node[TARGET,fill=white] at ($(I.north) +(0,0.5cm)$) {Staging Area};\state{12,0}{color_local}{L}\node[TARGET,fill=white] at ($(L.north) +(0,0.5cm)$) {Local Repository};\node [anchor=north west] at ($(W) +(-1cm,-1cm)$) (W0) {\begin{tikzpicture}[dirtree,TREE]\node {} child {node {file 1}};\end{tikzpicture}};%\draw[decorate,decoration={brace,amplitude=5pt},very thick] ($(W0.north) + (-1cm,-1cm)$) -- ($(W0.south) + (-1cm,0.2cm)$);\node [anchor=north west] at ($(W) +(-1cm,-1cm)$) (W0) {\begin{tikzpicture}[dirtree,TREE]\node {} child { node {file 1}};\end{tikzpicture}};%\draw[decorate,decoration={brace,amplitude=5pt},very thick] ($(W0.north) + (-1cm,-1cm)$) -- ($(W0.south) + (-1cm,0.2cm)$);\node [anchor=north west] at ($(I) +(-1cm,-1cm)$) (W0) {\begin{tikzpicture}[dirtree,TREE,text=gray,color=gray]\node {} child { node {file 1}};\end{tikzpicture}};\node [anchor=north west] at ($(L) +(-1cm,-1cm)$) (L0) {\begin{tikzpicture}[dirtree,TREE]\node {} child { node {file 1}};\end{tikzpicture}};\draw[decorate,decoration={brace,amplitude=5pt},very thick] ($(L0.north) + (1.3cm,-0.2cm)$) -- ($(L0.south) + (1.3cm,0.0cm)$);\node [TREE,anchor=west] at ($(L0) +(1.5,-0.1)$) {committed snapshot 1}; \end{tikzpicture}```::: {.callout-note collapse="true"}## Additional details about the commitThe following modifications have occurred (in reverse order to howthey actually occur):- The **main** _branch_ reference was created. There is currently only a single branch (more on branches later). The branch reference point to (indicates) which commit is the current commit within a branch.```{bash}#| label: git-commit1a#| echo: !expr -1#| eval: true#| cache: false#| classes: bash#| engine: bashcd ~/tmp/Repo1cat .git/refs/heads/main```- A **commit** was created. This points to a **tree** (which itself points to the blob representing `file1`) as well as other important metadata (such as who made the commit and when). Since the time stamp will be unique each time a snapshot is commited, so too the name of the commit (as a SHA-1 checksum hash) will differ. **To reiterate, the names of blobs and trees are determined by contents alone, commit names are also incorporate commit timestamp and details of the committer - and are thus virtually unique**.```{r}#| label: bash1#| echo: false#| eval: true#| cache: false hash =scan('~/tmp/Repo1/.git/refs/heads/main', what='character') hash_commit =strtrim(hash, width=5) knit_engines$set(bash1=function(options) { engine=options$engine options$code =gsub('#',hash_commit,options$code) code =paste("bash -c",shQuote(paste(options$code, collapse="\n"))) code =paste(options$engine_opts,code) out =system(code,intern=TRUE)engine_output(options,options$code,out) })``````{r, replace=TRUE}#| label: git-commit1b#| echo: !expr -1#| eval: false#| cache: false#| classes: bash#| engine: bash1 cd ~/tmp/Repo1 git cat-file commit #```- A **tree** object was created. This represents the directory tree of the snapshot (commit) and thus points to the **blob**s.```{r, replace=TRUE}#| label: git-commit1c#| echo: !expr -1#| eval: true#| cache: false#| classes: bash#| engine: bash1 cd ~/tmp/Repo1 git ls-tree #``` Or most commonly (if interested in the latest commit):```{r, replace=FALSE}#| label: git-commit1d#| echo: !expr -1#| eval: true#| cache: false#| classes: bash#| engine: bash1 cd ~/tmp/Repo1 git ls-tree HEAD```::: The schematic now looks like```{cat}#| label: Fig-advanced3#| echo: true#| class: tikz #| engine.opts:#| file: "resources/Fig-advanced3.tikz"\documentclass{minimal}\usepackage[paperwidth=35cm,paperheight=10cm,hmargin=0cm,vmargin=0cm]{geometry}%\usepackage[hmargin=0cm,vmargin=0cm]{geometry}\usepackage{fontspec}\usepackage[xelatex,active,tightpage]{preview}\renewcommand{\baselinestretch}{0.75}\usepackage{tikz}\usetikzlibrary{shapes,arrows,shadows,positioning,mindmap,backgrounds,decorations, calc,fit, decorations.pathreplacing,decorations.pathmorphing, shadings,shapes.geometric,patterns}\begin{document}\include{preview}\begin{preview}\usetikzlibrary{arrows.meta}\definecolor{color_workspace}{rgb}{0.12,0.6,0.51}\definecolor{color_tree}{HTML}{9ACD32}%\definecolor{color_tree}{rgb}{0.78,0.86,0.27}\definecolor{color_commit}{rgb}{0.9,0.9,0.2}\definecolor{color_remote}{rgb}{1,0.55,0.15}\definecolor{color_master}{rgb}{0.36,0.27,0.87}\definecolor{color_head}{HTML}{6495ED}%\definecolor{color_head}{HTML}{6495ED}\definecolor{color_index}{HTML}{E0FFFF}%\definecolor{color_index}{rgb}{1,1,1}\definecolor{color_file}{rgb}{1,1,1}\tikzstyle{TARGET}=[font={\fontspec[Scale=2]{NotoSans-Regular}}]\tikzstyle{CODE}=[font={\fontspec[Scale=2]{InconsolataSemiCondensed-Regular}}]\tikzstyle{TREE}=[font={\fontspec[Scale=1.5]{InconsolataSemiCondensed-Regular}}]\tikzstyle{fileText}=[font={\fontspec[Scale=1.1]{InconsolataSemiCondensed-Regular}}]%Define a file \newcommand{\file}[4]{\def\corner{0.15in};\def\cornerradius{0.02in};\def\lwidth{0.02in};\def\h{0.5in};\def\w{0.85in};\def\nline{0};\def\iconmargin{0.1in};\def\topmargin{0.3in};\node at (#1){\begin{tikzpicture}\coordinate (nw) at ($(-0.05in*1,-0.15in*1)$);\coordinate (#3) at (#1);\coordinate (ne0) at ($(nw)+(\w,0)$);\coordinate (ne1) at ($(ne0)-(\corner,0)$);\coordinate (ne2) at ($(ne0)-(0, \corner)$);\coordinate (se) at ($(ne0)+(0,-\h)$);\filldraw [-, line width = \lwidth, fill=#4](nw)--(ne1)--(ne2)[rounded corners=\cornerradius]--(se)--(nw|-se)-- cycle;\draw [-, line width = \lwidth](ne1)[rounded corners=\cornerradius]--(ne1|-ne2)--(ne2);\node [anchor=north west,TREE] at (nw){#2};\foreach \k in {0,...,\nline}{\draw [-, line width = \lwidth, line cap=round]($(nw|-se)+(\iconmargin,\iconmargin)+(0,{(\k-1)/(\nline-1)*(\h - \iconmargin - \topmargin)})$)--++($(\w,0)-2*(\iconmargin,0)$);}\end{tikzpicture}};}% end of file definition\begin{tikzpicture}\coordinate (G_ul) at (0,0);\coordinate (G_ll) at ($(G_ul)+(0,-10)$);\coordinate (G_lr) at ($(G_ll)+(4,0)$);\coordinate (G_ur) at ($(G_ul)+(4,0)$);\node[TREE,anchor=west] at ($(G_ul)+(0,-0.5)$)(git){.git/};\file{$(git.west)+(1.5,-2)$}{HEAD}{HEAD}{color_head}\file{$(HEAD)+(0,-2)$}{index}{index}{color_index}\draw[](G_ul)--(G_ll)--(G_lr)--(G_ur)-- cycle;%refs\node[TREE,anchor=west] at ($(G_ul)+(-5,-0.5)$)(git_ref){.git/refs/};\file{$(git_ref.west)+(1.5,-2)$}{\textcolor{white}{master}}{master}{color_master}\draw[]($(G_ul)+(-5,0)$)--++(0,-10)--++(4.9,0)--++(0,10)-- cycle;%objects\node[TREE,anchor=west] at ($(G_ul)+(-17,-0.5)$)(git_object){.git/objects/};\file{$(git_object.west)+(1.5,-2)$}{\textcolor{black}{hashblob}}{blob1}{color_workspace}\draw[]($(G_ul)+(-17,0)$)--++(0,-10)--++(11.9,0)--++(0,10)-- cycle;%trees\file{$(blob1.west)+(5,0)$}{\textcolor{black}{hashtree}}{tree1}{color_tree}%commits\file{$(tree1.west)+(3,0)$}{\textcolor{black}{hashcommit}}{commit1}{color_commit}%files\node[TREE,anchor=west] at ($(G_ul)+(-21,-0.5)$)(root){/};\file{$(root.west)+(1.7,-2)$}{\textcolor{black}{file1}}{file1}{color_file}\draw [very thick](root)--(root |- file1)--++(0.2,0);\begin{pgfonlayer}{background}\draw[fill=color_workspace!20]($(G_ul)+(-21,0)$)--++(0,-10)--++(3.9,0)--++(0,10)-- cycle;\end{pgfonlayer}%arrows\draw[->,very thick]($(HEAD)+(-1,0)$)--($(master)+(1.2,0)$);\draw[->,very thick]($(master)+(-1,0)$)--($(commit1)+(1.2,0)$);\draw[->,very thick]($(commit1)+(-1,0)$)--($(tree1)+(1.2,0)$);\draw[->,very thick]($(tree1)+(-1,0)$)--($(blob1)+(1.2,0)$);\draw[->,very thick,solid]($(index)+(-1,0)$)--($(blob1)+(1.2,0)$);\end{tikzpicture}\end{preview}\end{document}``````{r, cache=FALSE, echo=FALSE, results='asis'}library(knitr)#commithash =scan('~/tmp/Repo1/.git/refs/heads/main', what='character')hash_commit =strtrim(hash, width=5)#treehash =system(paste0('cd ~/tmp/Repo1; git cat-file -p ',hash_commit), intern=TRUE)hash =read.table(textConnection(hash[1]))hash_tree =strtrim(hash$V2,5)#blobhash =system('cd ~/tmp/Repo1; git ls-files --stage', intern=TRUE)hash =read.table(textConnection(hash))hash_blob =strtrim(hash$V2,5)system(paste0("sed -i 's/hashblob/",hash_blob,"/g' resources/Fig-advanced3.tikz"))system(paste0("sed -i 's/hashtree/",hash_tree,"/g' resources/Fig-advanced3.tikz"))system(paste0("sed -i 's/hashcommit/",hash_commit,"/g' resources/Fig-advanced3.tikz"))system("xelatex -output-directory=resources resources/Fig-advanced3.tikz")system("convert +repage -density 300 -resize 20% resources/Fig-advanced3.pdf resources/Fig-advanced3.png")```::: {.callout-note collapse="true"}## Another visual representation of the git```{bash}#| label: gitDraw3#| engine: bash#| echo: false./resources/git-draw--image-only--sha1-length 5 --hide-legend--hide-reflogs--git-dir ~/tmp/Repo1/.git --image-filename 10_git_files/figure-html/drawGit3.png ```:::::: {.callout-note collapse="true"}## More information about committing changes to the repositoryCommitting staged changes creates an object under the `.git` tree.```{r, replace=TRUE}#| label: git-add3a#| echo: !expr -1#| eval: true#| cache: false#| classes: bash#| engine: bash1cd ~/tmp/Repo1tree -a --charset unicode``````{r, replace=TRUE}#| label: git-add3b#| echo: !expr -1#| eval: true#| cache: false#| classes: bash#| engine: bash1cd ~/tmp/Repo1git cat-file -p HEAD``````{r, replace=TRUE}#| label: git-add3c#| echo: !expr -1#| eval: true#| cache: false#| classes: bash#| engine: bash1cd ~/tmp/Repo1git cat-file -p HEAD^{tree}``````{r, replace=TRUE}#| label: git-add3d#| echo: !expr -1#| eval: true#| cache: false#| classes: bash#| engine: bash1cd ~/tmp/Repo1git log --oneline```:::## More changes```{tikz}%| label: Fig2b%| engine: tikz%| echo: false%| cache: true%| dependson: common%| include: false%| class: tikz%| engine-opts:%| template: "resources/tikz-minimal.tex"\input{resources/common.tikz}\tikzstyle{refText} = [font={\fontspec[Scale=1.1]{InconsolataSemiCondensed-Regular}}] \begin{tikzpicture}\commit{}{A}{color_inactive}{}{}\draw [-,line width=3pt,draw=black!60] (A) -- ++(-1,0);\commit{right = 1cm of A}{B}{color_commit}{}{}\draw [-,line width=3pt,draw=black!60] (B) -- (A);\master{right = 0.5cm of B}\draw[->,line width=3pt,draw=black!60] (master) -- (B);\HEAD{right = 0.5cm of master}\draw[->,line width=3pt,draw=black!60] (HEAD) -- (master);\end{tikzpicture} ``````{bash}#| label: Fig2b-conv#| cache: false#| echo: falseconvert-trim +repage -density 300 -resize 20% 10_git_files/figure-html/Fig2b-1.pdf 10_git_files/figure-html/Fig2b-1.png ```Whenever a file is added or modified, if the changes are to betracked, the file needs to be added to the staging area. Letsdemonstrate by modifying `file1` and adding an additionalfile (`file2`), this time to a subdirectory (`dir1`).::: {.panel-tabset}### Terminal```{bash}#| label: git-add4#| echo: !expr -1#| eval: true#| cache: false#| classes: bash#| engine: bashcd ~/tmp/Repo1echo'---------------'>> file1mkdir dir1echo'* Notes'> dir1/file2git add file1 dir1/file2```Now if we re-examine the status:```{bash}#| label: git-add5#| echo: !expr -1#| eval: true#| cache: false#| classes: bash#| engine: bashcd ~/tmp/Repo1git status```### Rstudio1. modify `file1` by adding a number of hyphens under the `File 1` like in the figure below2. save the file. As you do so, you should notice that the file reappears in the status panel (this time with a blue "M" to signify that the file has been modified)3. to create the subdirectory, click on the "Add a new folder" icon and then enter a name for the subdirectory in the popup box (as per figure below)4. navigate to this new directory (`dir1`)5. click the "Create a new blank file in current directory" button and select "Text file"6. enter a new filename (`file2`) into the popup box7. enter some text into this file (like in the figure below)8. save the file and notice that the `dir1` directory is now also in the git status panel (yet its status is "untracked")9. stage both `file1` and `dir1` (click on the corresponding checkboxes):::And now our schematic looks like:```{cat}#| label: Fig-advanced4#| echo: true#| class: tikz #| engine.opts:#| file: "resources/Fig-advanced4.tikz"\documentclass{minimal}\usepackage[paperwidth=35cm,paperheight=10cm,hmargin=0cm,vmargin=0cm]{geometry}%\usepackage[hmargin=0cm,vmargin=0cm]{geometry}\usepackage{fontspec}\usepackage[xelatex,active,tightpage]{preview}\renewcommand{\baselinestretch}{0.75}\usepackage{tikz}\usetikzlibrary{shapes,arrows,shadows,positioning,mindmap,backgrounds,decorations, calc,fit, decorations.pathreplacing,decorations.pathmorphing, shadings,shapes.geometric,patterns}\begin{document}\include{preview}\begin{preview}\usetikzlibrary{arrows.meta}\definecolor{color_workspace}{rgb}{0.12,0.6,0.51}\definecolor{color_tree}{HTML}{9ACD32}%\definecolor{color_tree}{rgb}{0.78,0.86,0.27}\definecolor{color_commit}{rgb}{0.9,0.9,0.2}\definecolor{color_remote}{rgb}{1,0.55,0.15}\definecolor{color_master}{rgb}{0.36,0.27,0.87}\definecolor{color_head}{HTML}{6495ED}%\definecolor{color_head}{HTML}{6495ED}\definecolor{color_index}{HTML}{E0FFFF}%\definecolor{color_index}{rgb}{1,1,1}\definecolor{color_file}{rgb}{1,1,1}\tikzstyle{TARGET}=[font={\fontspec[Scale=2]{NotoSans-Regular}}]\tikzstyle{CODE}=[font={\fontspec[Scale=2]{InconsolataSemiCondensed-Regular}}]\tikzstyle{TREE}=[font={\fontspec[Scale=1.5]{InconsolataSemiCondensed-Regular}}]\tikzstyle{fileText}=[font={\fontspec[Scale=1.1]{InconsolataSemiCondensed-Regular}}]%Define a file \newcommand{\file}[4]{\def\corner{0.15in};\def\cornerradius{0.02in};\def\lwidth{0.02in};\def\h{0.5in};\def\w{0.85in};\def\nline{0};\def\iconmargin{0.1in};\def\topmargin{0.3in};\node at (#1){\begin{tikzpicture}\coordinate (nw) at ($(-0.05in*1,-0.15in*1)$);\coordinate (#3) at (#1);\coordinate (ne0) at ($(nw)+(\w,0)$);\coordinate (ne1) at ($(ne0)-(\corner,0)$);\coordinate (ne2) at ($(ne0)-(0, \corner)$);\coordinate (se) at ($(ne0)+(0,-\h)$);\filldraw [-, line width = \lwidth, fill=#4](nw)--(ne1)--(ne2)[rounded corners=\cornerradius]--(se)--(nw|-se)-- cycle;\draw [-, line width = \lwidth](ne1)[rounded corners=\cornerradius]--(ne1|-ne2)--(ne2);\node [anchor=north west,TREE] at (nw){#2};\foreach \k in {0,...,\nline}{\draw [-, line width = \lwidth, line cap=round]($(nw|-se)+(\iconmargin,\iconmargin)+(0,{(\k-1)/(\nline-1)*(\h - \iconmargin - \topmargin)})$)--++($(\w,0)-2*(\iconmargin,0)$);}\end{tikzpicture}};}% end of file definition\begin{tikzpicture}\coordinate (G_ul) at (0,0);\coordinate (G_ll) at ($(G_ul)+(0,-10)$);\coordinate (G_lr) at ($(G_ll)+(4,0)$);\coordinate (G_ur) at ($(G_ul)+(4,0)$);\node[TREE,anchor=west] at ($(G_ul)+(0,-0.5)$)(git){.git/};\file{$(git.west)+(1.5,-2)$}{HEAD}{HEAD}{color_head}\file{$(HEAD)+(0,-2)$}{index}{index}{color_index}\draw[](G_ul)--(G_ll)--(G_lr)--(G_ur)-- cycle;%refs\node[TREE,anchor=west] at ($(G_ul)+(-5,-0.5)$)(git_ref){.git/refs/};\file{$(git_ref.west)+(1.5,-2)$}{\textcolor{white}{master}}{master}{color_master}\draw[]($(G_ul)+(-5,0)$)--++(0,-10)--++(4.9,0)--++(0,10)-- cycle;%files\node[TREE,anchor=west] at ($(G_ul)+(-21,-0.5)$)(root){/};\file{$(root.west)+(1.7,-2)$}{\textcolor{black}{file1}}{file1}{color_file}%\file{$(root.west)+(1.7,-3.5)$}{\textcolor{black}{file2}}{file2}{color_file}\node[TREE,anchor=west] at ($(root |- file1)+(0.4,-2.5)$)(dir1){dir1/};\draw [very thick](root)--(root |- file1)--++(0.2,0);%\draw [very thick](root)--(root |- file2)--++(0.2,0);\draw [very thick](root)--(root |- dir1)--++(0.2,0);\file{$(dir1.west)+(1.7,-1.0)$}{\textcolor{black}{file2}}{file2}{color_file}\draw [very thick]($(dir1.west)+(0.2,-0.2)$)--($(dir1.west |- file2)+(0.2,0)$)--++(0.2,0);\begin{pgfonlayer}{background}\draw[fill=color_workspace!20]($(G_ul)+(-21,0)$)--++(0,-10)--++(3.9,0)--++(0,10)-- cycle;\end{pgfonlayer}%objects\node[TREE,anchor=west] at ($(G_ul)+(-17,-0.5)$)(git_object){.git/objects/};\file{$(git_object.west)+(1.5,-2)$}{\textcolor{black}{hashblob1}}{blob1}{color_workspace}\file{$(git_object.west)+(1.5,-3.5)$}{\textcolor{black}{hashblob3}}{blob2}{color_workspace}\file{$(git_object.west |- file2.north)+(1.5,-0)$}{\textcolor{black}{hashblob2}}{blob3}{color_workspace}\draw[]($(G_ul)+(-17,0)$)--++(0,-10)--++(11.9,0)--++(0,10)-- cycle;%trees\file{$(blob1.west)+(5,0)$}{\textcolor{black}{hashtree}}{tree1}{color_tree}%commits\file{$(tree1.west)+(3,0)$}{\textcolor{black}{hashcommit}}{commit1}{color_commit}%arrows\draw[->,very thick]($(HEAD)+(-1,0)$)--($(master)+(1.2,0)$);\draw[->,very thick]($(master)+(-1,0)$)--($(commit1)+(1.2,0)$);\draw[->,very thick]($(commit1)+(-1,0)$)--($(tree1)+(1.2,0)$);\draw[->,very thick]($(tree1)+(-1,0)$)--($(blob1)+(1.2,0)$);\draw[<-,very thick,dashed]($(blob2)+(-1.2,0)$)--($(file1)+(1.2,0)$);\draw[<-,very thick,dashed]($(blob3)+(-1.2,0)$)--($(file2)+(1.2,0)$);\draw[->,very thick]($(index)+(-1,0)$)--($(blob3)+(1.2,0)$);\draw[->,very thick]($(index)+(-1,0)$)--($(blob2)+(1.2,0)$);\end{tikzpicture}\end{preview}\end{document}``````{r, cache=FALSE, echo=FALSE, results='asis'}library(knitr)#commit hash =scan('~/tmp/Repo1/.git/refs/heads/main', what='character')hash_commits =strtrim(hash, width =5)#treehash =system(paste0('cd ~/tmp/Repo1; git cat-file -p ',hash_commits), intern=TRUE)hash =read.table(textConnection(hash[1]))hash_tree =strtrim(hash$V2, 5)#blobhash =system('cd ~/tmp/Repo1; git ls-files --stage', intern=TRUE)hash =read.table(textConnection(hash))hash_blob =c(hash_blob,strtrim(hash$V2,5))#hash_blob = strtrim(hash$V2,5)system(paste0("sed -i 's/hashblob1/", hash_blob[1], "/g' resources/Fig-advanced4.tikz"))system(paste0("sed -i 's/hashblob2/", hash_blob[2], "/g' resources/Fig-advanced4.tikz"))system(paste0("sed -i 's/hashblob3/", hash_blob[3], "/g' resources/Fig-advanced4.tikz"))system(paste0("sed -i 's/hashtree/",hash_tree,"/g' resources/Fig-advanced4.tikz"))system(paste0("sed -i 's/hashcommit/",hash_commits,"/g' resources/Fig-advanced4.tikz"))system("xelatex -output-directory=resources resources/Fig-advanced4.tikz")system("convert +repage -density 300 -resize 20% resources/Fig-advanced4.pdf resources/Fig-advanced4.png")```::: {.callout-note collapse="true"}## Another visual representation of the git```{bash}#| label: gitDraw4#| engine: bash#| cache: false#| echo: false./resources/git-draw--image-only--sha1-length 5 --hide-legend--hide-reflogs--git-dir ~/tmp/Repo1/.git --image-filename 10_git_files/figure-html/drawGit4.png ```:::::: {.callout-note collapse="true"}## More information about staging changes to the repositorySo when **staging**, the following has been performed:- the `index` file has been updated```{bash}#| label: git-modify1#| echo: !expr -1#| eval: true#| cache: false#| classes: bash#| engine: bashcd ~/tmp/Repo1git ls-files --stage```- two new _blobs_ have been generated. One representing the modified`file1` and the other representing the newly created `file2` in the`dir1` folder. The _blob_ that represented the original `file1` contents is still present and indeed is still the one currently committed. _Blobs_ are not erased or modified.:::Now we will commit this snapshot.::: {.panel-tabset}### Terminal```{bash}#| label: git-commit5#| echo: !expr -1#| eval: true#| cache: false#| classes: bash#| engine: bashcd ~/tmp/Repo1git commit -m'Modified file1 and added file2 (in dir1)'```### Rstudio1. click the "Commit" button2. you might like to explore the changes associated with each file3. enter a commit message (as in the figure below)4. click the "Commit" button5. after checking that the "Git Commit" popup does not contain any errors, close the popup6. to explore the repository history, click towards the "History" button on the top left corner of the "Review Changes" window This provides a graphical list of commits (in reverse chronological order)7. once you have finished exploring the history, you can close the "Review Changes" window:::::: {.callout-note collapse="true"}## More information about changes to the repositoryThe following modifications occur:- the _master_ branch now points to the new _commit_.```{bash}#| label: git-commit5a#| echo: !expr -1#| eval: true#| cache: false#| classes: bash#| engine: bashcd ~/tmp/Repo1cat .git/refs/heads/main``````{bash}#| label: git-commit5b#| echo: !expr -1#| eval: true#| cache: false#| classes: bash#| engine: bashcd ~/tmp/Repo1git reflog```- a new _commit_ was created. This points to a new root _tree_ object and also points to the previous _commit_ (its _parent_).```{r}#| label: bash2#| echo: false#| eval: true#| cache: false hash =scan('~/tmp/Repo1/.git/refs/heads/main', what='character') hash_commit =strtrim(hash, width=5) knit_engines$set(bash1=function(options) { engine=options$engine options$code =gsub('#',hash_commit,options$code) code =paste("bash -c",shQuote(paste(options$code, collapse="\n"))) code =paste(options$engine_opts,code) out =system(code,intern=TRUE)engine_output(options,options$code,out) })``````{r, replace=TRUE}#| label: git-commit2b#| echo: !expr -1#| eval: false#| cache: false#| classes: bash#| engine: bash1 cd ~/tmp/Repo1 git cat-file commit #```- new root _tree_ was created. This points to a _blob_ representing the modified `file1` as well as a newly created sub-directory _tree_ representing the `dir1` folder.```{r, replace=TRUE}#| label: git-commit2c#| echo: !expr -1#| eval: false#| cache: false#| classes: bash#| engine: bash1 cd ~/tmp/Repo1 git ls-tree 2b61e``````{r, replace=TRUE}#| label: git-commit2d#| echo: !expr -1#| eval: false#| cache: false#| classes: bash#| engine: bash1 cd ~/tmp/Repo1 git cat-file -p HEAD^{tree}```- a new sub-directory root _tree_ was created. This points to a _blob_ representing the modified `file1` as well as a newly created subtree _tree_ representing the`file2` file within the `dir1` folder.```{r, replace=TRUE}#| label: git-commit2e#| echo: !expr -1#| eval: false#| cache: false#| classes: bash#| engine: bash1 cd ~/tmp/Repo1 git ls-tree #``` OR,```{r, replace=TRUE}#| label: git-commit2f#| echo: !expr -1#| eval: false#| cache: false#| classes: bash#| engine: bash1 cd ~/tmp/Repo1 git ls-tree HEAD```:::```{cat}#| label: Fig-advanced5#| echo: true#| cache: false#| class: tikz #| engine.opts:#| file: "resources/Fig-advanced5.tikz"\documentclass{minimal}\usepackage[paperwidth=35cm,paperheight=10cm,hmargin=0cm,vmargin=0cm]{geometry}%\usepackage[hmargin=0cm,vmargin=0cm]{geometry}\usepackage{fontspec}\usepackage[xelatex,active,tightpage]{preview}\renewcommand{\baselinestretch}{0.75}\usepackage{tikz}\usetikzlibrary{shapes,arrows,shadows,positioning,mindmap,backgrounds,decorations, calc,fit, decorations.pathreplacing,decorations.pathmorphing, shadings,shapes.geometric,patterns}\begin{document}\include{preview}\begin{preview}\usetikzlibrary{arrows.meta}\definecolor{color_workspace}{rgb}{0.12,0.6,0.51}\definecolor{color_tree}{HTML}{9ACD32}%\definecolor{color_tree}{rgb}{0.78,0.86,0.27}\definecolor{color_commit}{rgb}{0.9,0.9,0.2}\definecolor{color_remote}{rgb}{1,0.55,0.15}\definecolor{color_master}{rgb}{0.36,0.27,0.87}\definecolor{color_head}{HTML}{6495ED}%\definecolor{color_head}{HTML}{6495ED}\definecolor{color_index}{HTML}{E0FFFF}%\definecolor{color_index}{rgb}{1,1,1}\definecolor{color_file}{rgb}{1,1,1}\tikzstyle{TARGET}=[font={\fontspec[Scale=2]{NotoSans-Regular}}]\tikzstyle{CODE}=[font={\fontspec[Scale=2]{InconsolataSemiCondensed-Regular}}]\tikzstyle{TREE}=[font={\fontspec[Scale=1.5]{InconsolataSemiCondensed-Regular}}]\tikzstyle{fileText}=[font={\fontspec[Scale=1.1]{InconsolataSemiCondensed-Regular}}]%Define a file \newcommand{\file}[4]{\def\corner{0.15in};\def\cornerradius{0.02in};\def\lwidth{0.02in};\def\h{0.5in};\def\w{0.85in};\def\nline{0};\def\iconmargin{0.1in};\def\topmargin{0.3in};\node at (#1){\begin{tikzpicture}\coordinate (nw) at ($(-0.05in*1,-0.15in*1)$);\coordinate (#3) at (#1);\coordinate (ne0) at ($(nw)+(\w,0)$);\coordinate (ne1) at ($(ne0)-(\corner,0)$);\coordinate (ne2) at ($(ne0)-(0, \corner)$);\coordinate (se) at ($(ne0)+(0,-\h)$);\filldraw [-, line width = \lwidth, fill=#4](nw)--(ne1)--(ne2)[rounded corners=\cornerradius]--(se)--(nw|-se)-- cycle;\draw [-, line width = \lwidth](ne1)[rounded corners=\cornerradius]--(ne1|-ne2)--(ne2);\node [anchor=north west,TREE] at (nw){#2};\foreach \k in {0,...,\nline}{\draw [-, line width = \lwidth, line cap=round]($(nw|-se)+(\iconmargin,\iconmargin)+(0,{(\k-1)/(\nline-1)*(\h - \iconmargin - \topmargin)})$)--++($(\w,0)-2*(\iconmargin,0)$);}\end{tikzpicture}};}% end of file definition\begin{tikzpicture}\coordinate (G_ul) at (0,0);\coordinate (G_ll) at ($(G_ul)+(0,-10)$);\coordinate (G_lr) at ($(G_ll)+(4,0)$);\coordinate (G_ur) at ($(G_ul)+(4,0)$);\node[TREE,anchor=west] at ($(G_ul)+(0,-0.5)$)(git){.git/};\file{$(git.west)+(1.5,-2)$}{HEAD}{HEAD}{color_head}\file{$(HEAD)+(0,-2)$}{index}{index}{color_index}\draw[](G_ul)--(G_ll)--(G_lr)--(G_ur)-- cycle;%refs\node[TREE,anchor=west] at ($(G_ul)+(-5,-0.5)$)(git_ref){.git/refs/};\file{$(git_ref.west)+(1.5,-2)$}{\textcolor{white}{master}}{master}{color_master}\draw[]($(G_ul)+(-5,0)$)--++(0,-10)--++(4.9,0)--++(0,10)-- cycle;%files\node[TREE,anchor=west] at ($(G_ul)+(-21,-0.5)$)(root){/};\file{$(root.west)+(1.7,-2)$}{\textcolor{black}{file1}}{file1}{color_file}\node[TREE,anchor=west] at ($(root |- file1)+(0.4,-2.5)$)(dir1){dir1/};\draw [very thick](root)--(root |- file1)--++(0.2,0);\draw [very thick](root)--(root |- dir1)--++(0.2,0);\file{$(dir1.west)+(1.7,-1.0)$}{\textcolor{black}{file2}}{file2}{color_file}\draw [very thick]($(dir1.west)+(0.2,-0.2)$)--($(dir1.west |- file2)+(0.2,0)$)--++(0.2,0);\begin{pgfonlayer}{background}\draw[fill=color_workspace!20]($(G_ul)+(-21,0)$)--++(0,-10)--++(3.9,0)--++(0,10)-- cycle;\end{pgfonlayer}%objects\node[TREE,anchor=west] at ($(G_ul)+(-17,-0.5)$)(git_object){.git/objects/};\file{$(git_object.west)+(1.5,-2)$}{\textcolor{black}{hashblob1}}{blob1}{color_workspace}\file{$(git_object.west)+(1.5,-3.5)$}{\textcolor{black}{hashblob3}}{blob2}{color_workspace}\file{$(git_object.west |- file2.north)+(1.5,-0)$}{\textcolor{black}{hashblob2}}{blob3}{color_workspace}\draw[]($(G_ul)+(-17,0)$)--++(0,-10)--++(11.9,0)--++(0,10)-- cycle;%trees\file{$(blob1.west)+(5,0)$}{\textcolor{black}{hashtree1}}{tree1}{color_tree}\file{$($(blob3.west)!0.5!(blob3.west)$)+(3,0)$}{\textcolor{black}{hashtree3}}{tree2}{color_tree}\file{$($(blob2.west)!0.5!(blob3.west)$)+(5.75,0)$}{\textcolor{black}{hashtree2}}{tree3}{color_tree}%commits\file{$(tree1.west)+(3,0)$}{\textcolor{black}{hashcommits1}}{commit1}{color_commit}\file{$(tree3.west)+(2.75,0)$}{\textcolor{black}{hashcommits2}}{commit2}{color_commit}%arrows\draw[->,very thick]($(HEAD)+(-1,0)$)--($(master)+(1.2,0)$);\draw[->,very thick]($(master)+(-1,0)$)--($(commit2)+(1.2,0)$);\draw[->,very thick]($(commit1)+(-1,0)$)--($(tree1)+(1.2,0)$);\draw[->,very thick]($(tree1)+(-1,0)$)--($(blob1)+(1.2,0)$);\draw[->,very thick]($(commit2)+(-1,0)$)--($(tree3)+(1.2,0)$);\draw[->,very thick]($(tree3)+(-1,0)$)--($(tree2)+(1.2,0)$);\draw[->,very thick]($(tree3)+(-1,0)$)--($(blob2)+(1.2,0)$);\draw[->,very thick]($(tree2)+(-1,0)$)--($(blob3)+(1.2,0)$);\draw[->,very thick]($(commit2)+(0,0.6)$)--($(commit1)+(0,-0.7)$);\draw[->,very thick]($(index)+(-1,0)$)--($(blob3)+(1.2,0)$);\draw[->,very thick]($(index)+(-1,0)$)--($(blob2)+(1.2,0)$);\end{tikzpicture}\end{preview}\end{document}``````{r, cache=FALSE, echo=FALSE, results='asis'}library(knitr)# commithash =scan("~/tmp/Repo1/.git/refs/heads/main", what ="character")hash_commits =c(hash_commits, strtrim(hash, width=5))# treehash =system(paste0("cd ~/tmp/Repo1; git cat-file -p ", hash_commits[2]), intern =TRUE)hash =read.table(textConnection(hash[1]))hash_tree =c(hash_tree, strtrim(hash$V2, 5))hash=system(paste0('cd ~/tmp/Repo1; git cat-file -p HEAD^{tree}'), intern=TRUE)hash =read.table(textConnection(hash))hash_tree =c(hash_tree, strtrim(hash$V3[hash$V2 =="tree"], 5))#blobhash =system('cd ~/tmp/Repo1; git ls-files --stage', intern=TRUE)hash =read.table(textConnection(hash))hash_blob =unique(c(hash_blob,strtrim(hash$V2,5)))system(paste0("sed -i 's/hashblob1/", hash_blob[1], "/g' resources/Fig-advanced5.tikz"))system(paste0("sed -i 's/hashblob2/", hash_blob[2], "/g' resources/Fig-advanced5.tikz"))system(paste0("sed -i 's/hashblob3/", hash_blob[3], "/g' resources/Fig-advanced5.tikz"))system(paste0("sed -i 's/hashtree1/", hash_tree[1], "/g' resources/Fig-advanced5.tikz"))system(paste0("sed -i 's/hashtree2/", hash_tree[2], "/g' resources/Fig-advanced5.tikz"))system(paste0("sed -i 's/hashtree3/", hash_tree[3], "/g' resources/Fig-advanced5.tikz"))system(paste0("sed -i 's/hashcommits1/", hash_commits[1], "/g' resources/Fig-advanced5.tikz"))system(paste0("sed -i 's/hashcommits2/", hash_commits[2], "/g' resources/Fig-advanced5.tikz"))system("xelatex -output-directory=resources resources/Fig-advanced5.tikz")system("convert +repage -density 300 -resize 20% resources/Fig-advanced5.pdf resources/Fig-advanced5.png")```::: {.callout-note collapse="true"}## Another visual representation of the git```{bash}#| label: gitDraw5#| engine: bash#| echo: false./resources/git-draw--image-only--sha1-length 5 --hide-legend--hide-reflogs--git-dir ~/tmp/Repo1/.git --image-filename 10_git_files/figure-html/drawGit5.png ```{width=100%}:::::: {.callout-note collapse="true"}## More information about committing changes to the repositoryCommitting staged changes creates an object under the `.git` tree.```{r, replace=TRUE}#| label: git-add5a#| echo: !expr -1#| eval: true#| cache: false#| classes: bash#| engine: bash1cd ~/tmp/Repo1tree -a --charset unicode``````{r, replace=TRUE}#| label: git-add5b#| echo: !expr -1#| eval: true#| cache: false#| classes: bash#| engine: bash1cd ~/tmp/Repo1git cat-file -p HEAD``````{r, replace=TRUE}#| label: git-add5c#| echo: !expr -1#| eval: true#| cache: false#| classes: bash#| engine: bash1cd ~/tmp/Repo1git cat-file -p HEAD^{tree}``````{r, replace=TRUE}#| label: git-add5d#| echo: !expr -1#| eval: true#| cache: false#| classes: bash#| engine: bash1cd ~/tmp/Repo1git log --oneline```:::Now you might be wondering... What if I have modified many files and Iwant to stage them all. Do I really have to add each fileindividually? Is there not some way to add multiple files at a time?The answer of course is yes. To stage all files (including those insubdirectories) we issue the `git add .` _command_ (notice the dot).```{bash}#| label: git-add6#| echo: !expr -1#| eval: false#| cache: false#| classes: bashcd ~/tmp/Repo1git add .```## `.gitignore`Whilst it is convenient to not have to list every file that you wantto be staged (added), what about files that we don't want to getstaged and committed. It is also possible to define a file (called`.gitignore`) that is a list of files (or file patterns) that are tobe excluded when we request all files be added. This functionality isprovided via the `.gitignore` _file_ that must be in the root of therepository working directory.For example, we may have temporary files or automatic backup files orfiles generated as intermediates in a compile process etc that getgenerated. These files are commonly generated in the process ofworking with files in a project, yet we do not necessarily wish forthem to be tracked. Often these files have very predictable filenamepattern (such as ending with a # or ~ symbol or having a specific fileextension such as .aux. As an example, when working with a project in Rstudio, files (such as`.Rhistory`) and directories (such as `.Rproj.user`) are automaticallyadded to the file system and thus appear as untracked files in gitstatus.Hence, we can create a`.gitignore` to exclude these files/directories.Indeed, if you are using Rstudio, you might have noticed that a`.gitignore` file was automatically created when you created theproject.Lets start by modifying the `file2` and creating a new file`f.tmp` (that we want to ignore).::: {.panel-tabset}### Terminal```{bash}#| label: git-add7#| echo: !expr -1#| eval: true#| cache: false#| classes: bash#| engine: bashcd ~/tmp/Repo1echo'---'>> dir1/file2echo'temp'> dir1/f.tmp```### Rstudio1. navigate to the `dir1` directory and open `file2` for editing (or just make sure you are on the `file2` tab.2. edit the file such that it just contains three hyphens (`---`) before saving the file3. in the same `dir1` directory add another new text file (`f.tmp`) and edit this file to contain the word `temp` (then save the file)The Git status panel should display both of these as untracked files.:::To ignore the `f.tmp` file, we could either explicitly addthis file as a row in a `.gitignore` file, or else we couldsupply a wildcard version that will ignore all files ending in`.tmp`.::: {.panel-tabset}### Terminal```{bash}#| label: git-ignore1#| echo: !expr -1#| eval: true#| cache: false#| classes: bash#| engine: bashcd ~/tmp/Repo1echo'*.tmp'> .gitignorecat .gitignore```### Rstudio1. navigate back to the root of the project2. click on the `gitignore` file to open it up for editing3. navigate to the end of this file and add a newline containing the text `*.tmp`You will notice that this `.gitignore` file already had items in itbefore you started editing it. These were added by Rstudio when youfirst created the new project.The first item is `.Rproj.user` and its presence in this file is whyit does not appear in the git status panel.Once we save the `.gitignore` file, notice how the `f.tmp` file issimilarly removed from the git status panel - since via `.gitignore`we have indicated that we want to ignore this file (not track it aspart of our version control system).:::::: {.callout-note collapse="true"}## More information about exclusions (`.gitignore`)| Entry | Meaning ||----------------|------------------------------------------------------------------------------------------------------------------------|| `file1` | DO NOT stage (add) file1 || `*.tmp` | DO NOT stage (add) any file ending in .tmp || `/dir1/*` | DO NOT stage (add) the folder called dir1 (or any of its contents) unless this is specifically negated (see next line) || `!/dir1/file2` | DO stage (add) the file called file2 in the dir1 folder |: {.primary .bordered .sm .paramsTable}:::Now when we go to add all files to the staging area, those that fallunder the exclude rules will be _ignored_::: {.panel-tabset}### Terminal```{bash}#| label: gitgitignore2#| echo: !expr -1#| eval: true#| cache: false#| classes: bashcd ~/tmp/Repo1git add .``````{bash}#| label: gitgitignore3#| echo: !expr -1#| eval: true#| cache: false#| classes: bashcd ~/tmp/Repo1git status```You will notice that `.gitignore` was added as a _new file_ and`dir1/file2` was marked as _modified_ yet `dir1/f.tmp` was totallyignored.### RstudioYou will notice that `.gitignore` was added as a _new file_ and`dir1/file2` was marked as _modified_ yet `dir1/f.tmp` was totallyignored.1. check the boxes next to each of the files listed in the status panel:::Lets now commit these changes.::: {.panel-tabset}### Terminal```{bash}#| label: gitgitignore4#| echo: !expr -1#| eval: true#| cache: false#| classes: bashcd ~/tmp/Repo1git commit -m'Modified file2, added .gitignore'``````{bash}#| label: gitgitignore5#| echo: !expr -1#| eval: true#| cache: false#| classes: bashcd ~/tmp/Repo1git status```### Rstudio1. click on the "Commit" button2. add a commit message (such as `Modified file2, added .gitignore`)3. click the "Commit" button4. close the popup5. close the "Review Changes" window:::For those still interested in the schematic...```{cat}#| label: Fig-advanced6#| echo: true#| cache: false#| class: tikz #| engine.opts:#| file: "resources/Fig-advanced6.tikz"\documentclass{minimal}\usepackage[paperwidth=35cm,paperheight=10cm,hmargin=0cm,vmargin=0cm]{geometry}%\usepackage[hmargin=0cm,vmargin=0cm]{geometry}\usepackage{fontspec}\usepackage[xelatex,active,tightpage]{preview}\renewcommand{\baselinestretch}{0.75}\usepackage{tikz}\usetikzlibrary{shapes,arrows,shadows,positioning,mindmap,backgrounds,decorations, calc,fit, decorations.pathreplacing,decorations.pathmorphing, shadings,shapes.geometric,patterns}\begin{document}\include{preview}\begin{preview}\usetikzlibrary{arrows.meta}\definecolor{color_workspace}{rgb}{0.12,0.6,0.51}\definecolor{color_tree}{HTML}{9ACD32}%\definecolor{color_tree}{rgb}{0.78,0.86,0.27}\definecolor{color_commit}{rgb}{0.9,0.9,0.2}\definecolor{color_remote}{rgb}{1,0.55,0.15}\definecolor{color_master}{rgb}{0.36,0.27,0.87}\definecolor{color_head}{HTML}{6495ED}%\definecolor{color_head}{HTML}{6495ED}\definecolor{color_index}{HTML}{E0FFFF}%\definecolor{color_index}{rgb}{1,1,1}\definecolor{color_file}{rgb}{1,1,1}\tikzstyle{TARGET}=[font={\fontspec[Scale=2]{NotoSans-Regular}}]\tikzstyle{CODE}=[font={\fontspec[Scale=2]{InconsolataSemiCondensed-Regular}}]\tikzstyle{TREE}=[font={\fontspec[Scale=1.5]{InconsolataSemiCondensed-Regular}}]\tikzstyle{fileText}=[font={\fontspec[Scale=1.1]{InconsolataSemiCondensed-Regular}}]%Define a file \newcommand{\file}[4]{\def\corner{0.15in};\def\cornerradius{0.02in};\def\lwidth{0.02in};\def\h{0.5in};\def\w{0.85in};\def\nline{0};\def\iconmargin{0.1in};\def\topmargin{0.3in};\node at (#1){\begin{tikzpicture}\coordinate (nw) at ($(-0.05in*1,-0.15in*1)$);\coordinate (#3) at (#1);\coordinate (ne0) at ($(nw)+(\w,0)$);\coordinate (ne1) at ($(ne0)-(\corner,0)$);\coordinate (ne2) at ($(ne0)-(0, \corner)$);\coordinate (se) at ($(ne0)+(0,-\h)$);\filldraw [-, line width = \lwidth, fill=#4](nw)--(ne1)--(ne2)[rounded corners=\cornerradius]--(se)--(nw|-se)-- cycle;\draw [-, line width = \lwidth](ne1)[rounded corners=\cornerradius]--(ne1|-ne2)--(ne2);\node [anchor=north west,TREE] at (nw){#2};\foreach \k in {0,...,\nline}{\draw [-, line width = \lwidth, line cap=round]($(nw|-se)+(\iconmargin,\iconmargin)+(0,{(\k-1)/(\nline-1)*(\h - \iconmargin - \topmargin)})$)--++($(\w,0)-2*(\iconmargin,0)$);}\end{tikzpicture}};}% end of file definition\begin{tikzpicture}\coordinate (G_ul) at (0,0);\coordinate (G_ll) at ($(G_ul)+(0,-10)$);\coordinate (G_lr) at ($(G_ll)+(4,0)$);\coordinate (G_ur) at ($(G_ul)+(4,0)$);\node[TREE,anchor=west] at ($(G_ul)+(0,-0.5)$)(git){.git/};\file{$(git.west)+(1.5,-2)$}{HEAD}{HEAD}{color_head}\file{$(HEAD)+(0,-2)$}{index}{index}{color_index}\draw[](G_ul)--(G_ll)--(G_lr)--(G_ur)-- cycle;%refs\node[TREE,anchor=west] at ($(G_ul)+(-5,-0.5)$)(git_ref){.git/refs/};\file{$(git_ref.west)+(1.5,-2)$}{\textcolor{white}{master}}{master}{color_master}\draw[]($(G_ul)+(-5,0)$)--++(0,-10)--++(4.9,0)--++(0,10)-- cycle;%files\node[TREE,anchor=west] at ($(G_ul)+(-21,-0.5)$)(root){/};\file{$(root.west)+(1.7,-2)$}{\textcolor{black}{file1}}{file1}{color_file}\node[TREE,anchor=west] at ($(root |- file1)+(0.4,-2.2)$)(dir1){dir1/};\draw [very thick](root)--(root |- file1)--++(0.2,0);\draw [very thick](root)--(root |- dir1)--++(0.2,0);\file{$(dir1.west)+(1.7,-1.0)$}{\textcolor{black}{file2}}{file2}{color_file}\draw [very thick]($(dir1.west)+(0.2,-0.2)$)--($(dir1.west |- file2)+(0.2,0)$)--++(0.2,0);\file{$(file2.west)+(0,-1.5)$}{\textcolor{black!70}{f.tmp}}{file3}{color_file}\draw [very thick]($(dir1.west)+(0.2,-0.2)$)--($(dir1.west |- file3)+(0.2,0)$)--++(0.2,0);\file{$(root.west)+(1.7,-8.5)$}{\textcolor{black}{.giti.}}{file4}{color_file}\draw [very thick](root)--(root |- file4)--++(0.2,0);\begin{pgfonlayer}{background}\draw[fill=color_workspace!20]($(G_ul)+(-21,0)$)--++(0,-10)--++(3.9,0)--++(0,10)-- cycle;\end{pgfonlayer}%objects\node[TREE,anchor=west] at ($(G_ul)+(-17,-0.5)$)(git_object){.git/objects/};\file{$(git_object.west)+(1.5,-2)$}{\textcolor{black}{hashblob1}}{blob1}{color_workspace!20}\file{$(git_object.west)+(1.5,-3.5)$}{\textcolor{black}{hashblob3}}{blob2}{color_workspace}\file{$(git_object.west |- file2.north)+(1.5,-0)$}{\textcolor{black}{hashblob2}}{blob3}{color_workspace!20}\file{$(git_object.west |- file3.north)+(1.5,0)$}{\textcolor{black}{hashblob5}}{blob4}{color_workspace}\file{$(git_object.west |- file4.north)+(1.5,0)$}{\textcolor{black}{hashblob4}}{blob5}{color_workspace}\draw[]($(G_ul)+(-17,0)$)--++(0,-10)--++(11.9,0)--++(0,10)-- cycle;%trees\file{$(blob1.west)+(5,0)$}{\textcolor{black}{hashtree1}}{tree1}{color_tree!20}\file{$($(blob3.west)!0.5!(blob3.west)$)+(3,0)$}{\textcolor{black}{hashtree3}}{tree2}{color_tree!20}\file{$($(blob2.west)!0.5!(blob3.west)$)+(5.75,0)$}{\textcolor{black}{hashtree2}}{tree3}{color_tree!20}\file{$($(blob4.west)!0.5!(blob4.west)$)+(3,0)$}{\textcolor{black}{hashtree5}}{tree4}{color_tree}\file{$($(blob4.west)!0.5!(blob5.west)$)+(5.75,0)$}{\textcolor{black}{hashtree4}}{tree5}{color_tree}%commits\file{$(tree1.west)+(3,0)$}{\textcolor{black}{hashcommits1}}{commit1}{color_commit!20}\file{$(tree3.west)+(2.75,0)$}{\textcolor{black}{hashcommits2}}{commit2}{color_commit!20}\file{$(tree5.west)+(2.75,0)$}{\textcolor{black}{hashcommits3}}{commit3}{color_commit}%arrows\draw[->,very thick,draw=black]($(HEAD)+(-1,0)$)--($(master)+(1.2,0)$);\draw[->,very thick]($(master)+(-1,0)$)--($(commit3)+(1.2,0)$);\draw[->,very thick,draw=gray]($(commit1)+(-1,0)$)--($(tree1)+(1.2,0)$);\draw[->,very thick,draw=gray]($(tree1)+(-1,0)$)--($(blob1)+(1.2,0)$);\draw[->,very thick,draw=gray]($(commit2)+(-1,0)$)--($(tree3)+(1.2,0)$);\draw[->,very thick,draw=gray]($(tree3)+(-1,0)$)--($(tree2)+(1.2,0)$);\draw[->,very thick,draw=gray]($(tree3)+(-1,0)$)--($(blob2)+(1.2,0)$);\draw[->,very thick,draw=gray]($(tree2)+(-1,0)$)--($(blob3)+(1.2,0)$);\draw[->,very thick,draw=gray]($(commit2)+(0,0.6)$)--($(commit1)+(0,-0.7)$);\draw[->,very thick]($(commit3)+(-1,0)$)--($(tree5)+(1.2,0)$);\draw[->,very thick]($(tree5)+(-1,0)$)--($(tree4)+(1.2,0)$);\draw[->,very thick]($(tree5)+(-1,0)$)--($(blob5)+(1.2,0)$);\draw[->,very thick]($(tree4)+(-1,0)$)--($(blob4)+(1.2,0)$);\draw[->,very thick]($(tree5)+(-1,0)$)--($(blob2)+(1.2,0)$);\draw[->,very thick]($(commit3)+(0,0.6)$)--($(commit2)+(0,-0.7)$);\draw[<-,very thick,dashed]($(blob2)+(-1.2,0)$)--($(file1)+(1.2,0)$);\draw[<-,very thick,dashed]($(blob4)+(-1.2,0)$)--($(file2)+(1.2,0)$);\draw[<-,very thick,dashed]($(blob5)+(-1.2,0)$)--($(file4)+(1.2,0)$);\draw[->,very thick]($(index)+(-1,0)$)--($(blob3)+(1.2,0)$);\draw[->,very thick]($(index)+(-1,0)$)--($(blob2)+(1.2,0)$);\end{tikzpicture}\end{preview}\end{document}``````{r, cache=FALSE, echo=FALSE, results='asis'}library(knitr)#commit hash =scan('~/tmp/Repo1/.git/refs/heads/main', what='character')hash_commits =c(hash_commits, strtrim(hash, width =5))# treehash =system(paste0("cd ~/tmp/Repo1; git cat-file -p ", hash_commits[2]), intern =TRUE)hash =read.table(textConnection(hash[1]))hash_tree =c(hash_tree, strtrim(hash$V2, 5))hash =system(paste0('cd ~/tmp/Repo1; git cat-file -p HEAD^{tree}'), intern=TRUE)hash =read.table(textConnection(hash))hash_tree =c(hash_tree, strtrim(hash$V3[hash$V2 =="tree"], 5))#blobhash =system('cd ~/tmp/Repo1; git ls-files --stage', intern=TRUE)hash =read.table(textConnection(hash))hash_blob =unique(c(hash_blob,strtrim(hash$V2,5)))system(paste0("sed -i 's/hashblob1/", hash_blob[1], "/g' resources/Fig-advanced6.tikz"))system(paste0("sed -i 's/hashblob2/", hash_blob[2], "/g' resources/Fig-advanced6.tikz"))system(paste0("sed -i 's/hashblob3/", hash_blob[3], "/g' resources/Fig-advanced6.tikz"))system(paste0("sed -i 's/hashblob4/", hash_blob[4], "/g' resources/Fig-advanced6.tikz"))system(paste0("sed -i 's/hashblob5/", hash_blob[5], "/g' resources/Fig-advanced6.tikz"))system(paste0("sed -i 's/hashtree1/", hash_tree[1], "/g' resources/Fig-advanced6.tikz"))system(paste0("sed -i 's/hashtree2/", hash_tree[2], "/g' resources/Fig-advanced6.tikz"))system(paste0("sed -i 's/hashtree3/", hash_tree[3], "/g' resources/Fig-advanced6.tikz"))system(paste0("sed -i 's/hashtree4/", hash_tree[4], "/g' resources/Fig-advanced6.tikz"))system(paste0("sed -i 's/hashtree5/", hash_tree[5], "/g' resources/Fig-advanced6.tikz"))system(paste0("sed -i 's/hashcommits1/", hash_commits[1], "/g' resources/Fig-advanced6.tikz"))system(paste0("sed -i 's/hashcommits2/", hash_commits[2], "/g' resources/Fig-advanced6.tikz"))system(paste0("sed -i 's/hashcommits3/", hash_commits[3], "/g' resources/Fig-advanced6.tikz"))system("xelatex -output-directory=resources resources/Fig-advanced6.tikz")system("convert +repage -density 300 -resize 20% resources/Fig-advanced6.pdf resources/Fig-advanced6.png")```::: {.callout-note collapse="true"}## Another visual representation of the git```{bash}#| label: gitDraw6#| engine: bash#| cache: false#| echo: false./resources/git-draw--image-only--sha1-length 5 --hide-legend--hide-reflogs--git-dir ~/tmp/Repo1/.git --image-filename 10_git_files/figure-html/drawGit6.png ```{width=100%}:::::: {.callout-note collapse="true"}## More information about committing changes to the repositoryCommitting staged changes creates an object under the `.git` tree.```{r, replace=TRUE}#| label: git-add6a#| echo: !expr -1#| eval: true#| cache: false#| classes: bash#| engine: bash1cd ~/tmp/Repo1tree -a --charset unicode``````{r, replace=TRUE}#| label: git-add6b#| echo: !expr -1#| eval: true#| cache: false#| classes: bash#| engine: bash1cd ~/tmp/Repo1git cat-file -p HEAD``````{r, replace=TRUE}#| label: git-add6c#| echo: !expr -1#| eval: true#| cache: false#| classes: bash#| engine: bash1cd ~/tmp/Repo1git cat-file -p HEAD^{tree}``````{r, replace=TRUE}#| label: git-add6d#| echo: !expr -1#| eval: true#| cache: false#| classes: bash#| engine: bash1cd ~/tmp/Repo1git log --oneline```:::# Inspecting a repositoryFor this section, will will be working on the repository built up inthe previous section. If you did not follow along with the previoussection, I suggest that you expand the following callout and run theprovided code in a terminal.If you already have the repository, you can ignore the commands tocreate the repository.::: {.callout-note collapse="true"}## Commands to create the the repositoryIssue the following commands in your terminal```{bash}#| label: git_status1#| classes: bash#| engine: bash#| echo: true#| eval: falserm-rf ~/tmp/Repo1mkdir ~/tmp/Repo1cd ~/tmp/Repo1git init echo'File 1'> file1git add file1git commit -m'Initial repo and added file1'echo'---------------'>> file1mkdir dir1echo'* Notes'> dir1/file2git add file1 dir1/file2git commit -m'Modified file1 and added file2 (in dir1)'echo'---'>> dir1/file2echo'temp'> dir1/f.tmpecho'*.tmp'> .gitignoregit add .git commit -m'Modified file2, added .gitignore'``````{bash}#| label: git-status2a#| echo: !expr -1#| eval: true#| cache: false#| classes: bashcd ~/tmp/Repo1tree-ra-L 2 --charset ascii```:::## Status of workspace and staging areaRecall that within the .git environment, files can be in one of fourstates:- untracked- modified- staged- committedTo inspect the status of files in your workspace, you can issue the`git status`<i>command</i> (as we have done on numerous occasionsabove). This command displays the current state of the workspace andstaging area.::: {.panel-tabset}### Terminal```{bash}#| label: git_status2#| echo: !expr -1#| eval: true#| cache: false#| classes: bash#| engine: bashcd ~/tmp/Repo1git status```The output of `git status` partitions all the files into (staged:`Changes to be committed`, unstaged: `Changes not staged for commit`and `Untracked`) as well as hints on how to either promote or demotethe status of these files.### RstudioExamine the git status panel - ideally it should be empty therebysignalling that all your important files are tracked andcommitted.:::### log of commits::: {.panel-tabset}#### TerminalThe `git log` _command_ allows us to review the history of committedsnapshots```{bash}#| label: git_log#| echo: !expr -1#| eval: true#| cache: false#| classes: bash#| engine: bashcd ~/tmp/Repo1git log```We can see that in my case some fool called 'Murray Logan' has made atotal of three commits. We can also see the date/time that the commitswere made as well as the supplied commit comment.Over time repositories accumulate a large number of commits, to onlyreview the last 2 commits, we could issue the `git log -n2` _command_. ```{bash}#| label: git_log1#| echo: !expr -1#| eval: true#| cache: false#| classes: bash#| engine: bashcd ~/tmp/Repo1git log -n 2 ```::: {.callout-note collapse="true"}## Additional useful (`git log`) options<table><thead><th>Option</th><th>Example</th></thead><tbody><tr><td>`--oneline`<br>Condensed view</td><td>```{bash}#| label: git_log2a#| echo: !expr -1#| eval: true#| cache: false#| classes: bash#| engine: bashcd ~/tmp/Repo1git log --oneline```</td></tr><tr><td>`--stat`<br>Indicates number of changes</td><td>```{bash}#| label: git_log2b#| echo: !expr -1#| eval: true#| cache: false#| classes: bash#| engine: bashcd ~/tmp/Repo1git log --stat```</td></tr><tr><td>`-p`<br>Displays the full diff of each commit</td><td>```{bash}#| label: git_log2c#| echo: !expr -1#| eval: true#| cache: false#| classes: bash#| engine: bashcd ~/tmp/Repo1git log -p```</td></tr><tr><td>`--author="<name>"`<br>Filter by author</td><td>```{bash}#| label: git_log2d#| echo: !expr -1#| eval: true#| cache: false#| classes: bash#| engine: bashcd ~/tmp/Repo1git log --author="Murray"```</td></tr><tr><td>`--grep="<pattern>"`<br>Filter by regex pattern of commit message</td><td>```{bash}#| label: git_log2e#| echo: !expr -1#| eval: true#| cache: false#| classes: bash#| engine: bashcd ~/tmp/Repo1git log --grep="Modified"```</td></tr><tr><td>`<file>`<br>Filter by filename</td><td>```{bash}#| label: git_log2f#| echo: !expr -1#| eval: true#| cache: false#| classes: bash#| engine: bashcd ~/tmp/Repo1git log file1```</td></tr><tr><td>`--decorate --graph`</td><td>```{bash}#| label: git_log2g#| echo: !expr -1#| eval: true#| cache: false#| classes: bash#| engine: bashcd ~/tmp/Repo1git log --graph--decorate--oneline```</td></tr><tr><td>`--all`<br>All branches</td><td>```{bash}#| label: git_log2h#| echo: !expr -1#| eval: true#| cache: false#| classes: bash#| engine: bashcd ~/tmp/Repo1git log --all```</td></tr></tbody></table>:::#### RstudioTo explore the history of a repository, click on the clock icon ("Viewhistory of previous commits" button). This will open up the "ReviewChanges" window in the "History" tab.Along with the reverse chronological list of commits, for each commit(and file thereof), you can explore the changes (diffs) that occurred.Text that appears over a green background represents text that havebeen added as part of the current commit. Text that appears over a redbackground represents text that have been removed.If we scroll down and explore the changes in `dir1/file2` for the mostrecent commit, we see that the text `* Notes` was removed and then `*Notes` and `---` were added. At first this might seem a bit odd - whywas `* Notes` deleted and then added back? Git works on entire lines of text. So the first line was replacedbecause in the newer version, the first line had a carriage return(newline character). Although we cant see this character, it isthere - we see it more via its effect (sending the text after it tothe next line). Hence, in fact, two lines of text were actuallychanged in the most recent commit.:::### `reflog`::: {.panel-tabset}#### TerminalAnother way to explore the commit history is to look at the**reflog**. This is a log of the _branch_ references. This approach ismore useful when we have multiple _branches_ and so will be visited inthe <ahref="#Branching">section on branching</a>. It displays allrepository activity, not just the commits.```{bash}#| label: git_reflog1#| echo: !expr -1#| eval: true#| cache: false#| classes: bash#| engine: bashcd ~/tmp/Repo1git reflog```#### RstudioSome of this sort of information can be gleaned from the git"History". Just make sure you select ("all branches") from the "Switchbranch" menu.:::### `diff`Whilst some of these actions described in this section are availablefrom the "History" tab of the "Review Changes" window in Rstudio, mostare only available as terminal commands.```{tikz}%| label: Fig-advancedDiff1%| engine: tikz%| echo: false%| cache: true%| class: tikz%| engine-opts:%| template: "resources/tikz-minimal.tex"\usetikzlibrary{shapes,arrows,shadows,positioning,mindmap,backgrounds,decorations, calc,fit, decorations.pathreplacing,decorations.pathmorphing, shadings,shapes.geometric,patterns} \usetikzlibrary{arrows.meta}\tikzstyle{TARGET} = [font={\fontspec[Scale=2]{NotoSans-Regular}}] \tikzstyle{CODE} = [font={\fontspec[Scale=2]{InconsolataSemiCondensed-Regular}}] \tikzstyle{TREE} = [font={\fontspec[Scale=1.5]{InconsolataSemiCondensed-Regular}}] \tikzstyle{fileText} = [font={\fontspec[Scale=1.1]{InconsolataSemiCondensed-Regular}}] \definecolor{color_workspace}{rgb}{0.12,0.6,0.51}\definecolor{color_index}{rgb}{0.78,0.86,0.27}\definecolor{color_local}{rgb}{0.9,0.9,0.2}\definecolor{color_remote}{rgb}{1,0.55,0.15}\definecolor{color_master}{rgb}{0.36,0.27,0.87}\definecolor{color_head}{HTML}{6495ED} %\definecolor{color_head}{HTML}{6495ED}% A template for making the storage symbol\newcommand{\state}[3]{\draw (#1) node [draw=none,fill=#2,shape=circle,minimum width=2cm] (#3) {\begin{tikzpicture}\node [draw=white, fill=white,shape=cylinder,shape aspect=1.3 ,shape border rotate=90,minimum height=1.6cm,minimum width=1.5cm] at (0,0) (Cylinder) {}; \draw[draw=#2,very thick,line width=0.1cm,anchor=north west] ($(Cylinder.north west) +(-0.05cm,-0.1cm)$) arc (-180:0:0.8cm and 0.2cm); \draw[draw=#2,very thick,line width=0.1cm,anchor=north west] ($(Cylinder.north west) +(-0.05cm,-0.5cm)$) arc (-180:0:0.8cm and 0.2cm); \draw[draw=#2,very thick,line width=0.1cm,anchor=north west] ($(Cylinder.north west) +(-0.05cm,-0.9cm)$) arc (-180:0:0.8cm and 0.2cm); \end{tikzpicture}};}% Define dirtree\makeatletter\newcount\dirtree@lvl\newcount\dirtree@plvl\newcount\dirtree@clvl\def\dirtree@growth{%\ifnum\tikznumberofcurrentchild=1\relax\global\advance\dirtree@plvl by 1\expandafter\xdef\csname dirtree@p@\the\dirtree@plvl\endcsname{\the\dirtree@lvl}\fi\global\advance\dirtree@lvl by 1\relax\dirtree@clvl=\dirtree@lvl\advance\dirtree@clvl by -\csname dirtree@p@\the\dirtree@plvl\endcsname\pgf@xa=0.25cm\relax\pgf@ya=-0.5cm\relax\pgf@ya=\dirtree@clvl\pgf@ya\pgftransformshift{\pgfqpoint{\the\pgf@xa}{\the\pgf@ya}}%\ifnum\tikznumberofcurrentchild=\tikznumberofchildren\global\advance\dirtree@plvl by -1\fi}\tikzset{dirtree/.style={growth function=\dirtree@growth,every node/.style={anchor=north},every child node/.style={anchor=west},edge from parent path={(\tikzparentnode\tikzparentanchor) |- (\tikzchildnode\tikzchildanchor)}}}\makeatother%end of t%Define a file \newcommand{\file}[3] {\coordinate (#3) at (#1);\draw [anchor=top left](#1) rectangle ++(2,-2);\draw [fill=color_workspace]($(#1) +(2,0)$) -- ++(0,-0.5) --++(-0.5,0.5) -- cycle; \node [anchor=north west,fileText] at ($(#1) +(0.3,-0.3)$) {#2};}% end of file definition\begin{tikzpicture}\state{0,0}{color_workspace}{W}\node[TARGET,fill=white] at ($(W.north) +(0,0.5cm)$) {Workspace};\draw [line width=0.1cm,draw=color_workspace] (W.south) -- ++(0,-5); \state{8,0}{color_index}{I}\node[TARGET,fill=white] at ($(I.north) +(0,0.5cm)$) {Staging Area};\draw [line width=0.1cm,draw=color_index] (I.south) -- ++(0,-5); \state{16,0}{color_local}{L}\node[TARGET,fill=white] at ($(L.north) +(0,0.5cm)$) {Local Repository};\draw [line width=0.1cm,draw=color_local] (L.south) -- ++(0,-5); \draw[{Round Cap[length=0.5em]}-Triangle Cap,very thick, line width=1cm, draw=color_index] ($(W) + (0.1cm,-3)$) -- ($(I) + (-0.1cm,-3)$) node[anchor=west,pos=0, text=black,align=center,CODE] {git diff};\draw[{Round Cap[length=0.5em]}-Triangle Cap,very thick, line width=1cm, draw=color_local] ($(I) + (0.1cm,-3)$) -- ($(L) + (-0.1cm,-3)$) node[anchor=west,pos=0, text=black,align=center,CODE] {git diff --cached};\draw[{Round Cap[length=0.5em]}-Triangle Cap,very thick, line width=1cm, draw=color_local] ($(W) + (0.1cm,-5)$) -- ($(L) + (-0.1cm,-5)$) node[anchor=west,pos=0, text=black,align=center,CODE] {git diff HEAD};\end{tikzpicture}```Two of the three commits in our repository involved modifications to afile (`dir1/file2`). To further help illustrate commands to comparefiles indifferent states, we will additionally make a further changeto `dir1/file2`. The `git diff` allows us to explore differencesbetween:- the workspace and the staging area (index)```{bash}#| label: git_diff1#| echo: !expr -1#| eval: true#| cache: false#| classes: bash#| engine: bashcd ~/tmp/Repo1# lets modify dir1/file2echo'Notes'>> dir1/file2git diff``` The output indicates that we are comparing the blob representing`dir1/file2` in the <i>index</i> (staging area) with the newly modified `dir1/file2`. The next couple of rows indicate that the<i>indexed</i> version will be represented by a '-' sign and the new version will be represented by a '+' sign. The next row (which is surrounded in a pair of `@` signs, indicates that there are two lines that have changed. Finally the next two rows show that a charrage return has been added to the end of the first line and the new version has added the word 'Notes' to the next line.- the staging area and the last commit```{bash}#| label: git_diff3#| echo: !expr -1#| eval: true#| cache: false#| classes: bash#| engine: bashcd ~/tmp/Repo1git add .git diff --cached``` Once we stage the modifications, we see that the same differences are recorded.- the index and a tree (in this case, the current tree)```{bash}#| label: git_diff4#| echo: !expr -1#| eval: true#| cache: false#| classes: bash#| engine: bashcd ~/tmp/Repo1git diff --cached HEAD^{tree}```- the workspace and the current commit```{bash}#| label: git_diff5#| echo: !expr -1#| eval: true#| cache: false#| classes: bash#| engine: bashcd ~/tmp/Repo1git diff HEAD```- two commits (e.g. previous and current commits)```{bash}#| label: git_diff6#| echo: !expr -1#| eval: true#| cache: false#| classes: bash#| engine: bashcd ~/tmp/Repo1git diff HEAD^ HEAD```- two trees (first example, the current and previous commit trees)```{bash}#| label: git_diff7#| echo: !expr -1#| eval: true#| cache: false#| classes: bash#| engine: bashcd ~/tmp/Repo1git diff HEAD^{tree} HEAD^^{tree}``````{bash}#| label: git_diff8#| echo: !expr -1#| eval: true#| cache: false#| classes: bash#| engine: bashcd ~/tmp/Repo1git diff 07a94 2b61e```- two blobs (indeed any two objects)```{bash}#| label: git_diff9#| echo: !expr -1#| eval: true#| cache: false#| classes: bash#| engine: bashcd ~/tmp/Repo1git diff 50fcd 28ed2```### `ls-files`Similar to the previous section, the following is only reallyavailable via the terminal.We can list the files that comprise the repository by:```{bash}#| label: git_ls_files#| echo: !expr -1#| eval: true#| cache: false#| classes: bash#| engine: bashcd ~/tmp/Repo1git ls-files ```The change to `dir1/file2` above was just to illustrate the `gitdiff`. In doing so we now have a modified version of this file thathas not been committed Before we move on, I am going to remove thesechanges so that the `dir1/file2` is not in a modified state andreflects the state of the current commit. To do so, I will use performa **hard reset** (`git reset --hard`). More will be discussed aboutthe `git reset` command later in this tutorial - for now all that isimportant is to know that it restores the workspace to a previousstate.In addition to the `git reset --hard`, I will also clean and prune the repository.```{bash}#| label: git_ls_files1#| echo: !expr -1#| eval: true#| cache: false#| classes: bash#| engine: bashcd ~/tmp/Repo1git reset --hardgit clean -qfdxgit reflog expire --expire-unreachable=now --allgit gc --prune=now```